- changed smb_getpwnam() to use winbind style usernames
[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,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,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,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   /* if the username exists as a domain/username pair on the unix system then use 
857      that */
858   if (!Get_Pwnam(user, False)) {
859           pstring user2;
860           slprintf(user2,sizeof(user2),"%s/%s", domain, user);
861           if (Get_Pwnam(user2, True)) {
862                   DEBUG(3,("Using unix username %s\n", user2));
863                   pstrcpy(user, user2);
864           }
865   }
866
867   /*
868    * Pass the user through the NT -> unix user mapping
869    * function.
870    */
871    
872   (void)map_username(user);
873
874   /*
875    * Do any UNIX username case mangling.
876    */
877   smb_getpwnam(user, True);
878
879   add_session_user(user);
880
881   /*
882    * Check if the given username was the guest user with no password.
883    */
884
885   if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
886     guest = True;
887
888   /* 
889    * Check with orig_user for security=server and
890    * security=domain.
891    */
892
893   if (!guest && 
894                           !check_server_security(orig_user, domain, user,
895                                                                          smb_apasswd, smb_apasslen,
896                                                                          smb_ntpasswd, smb_ntpasslen) &&
897                           !check_domain_security(orig_user, domain, user,
898                              smb_apasswd, smb_apasslen,
899                              smb_ntpasswd, smb_ntpasslen) &&
900       !check_hosts_equiv(user)
901      )
902   {
903
904     /* 
905      * If we get here then the user wasn't guest and the remote
906      * authentication methods failed. Check the authentication
907      * methods on this local server.
908      *
909      * If an NT password was supplied try and validate with that
910      * first. This is superior as the passwords are mixed case 
911      * 128 length unicode.
912       */
913
914     if(smb_ntpasslen)
915     {
916       if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL))
917         DEBUG(2,("NT Password did not match for user '%s' ! Defaulting to Lanman\n", user));
918       else
919         valid_nt_password = True;
920     } 
921
922     if (!valid_nt_password && !password_ok(user, smb_apasswd,smb_apasslen,NULL))
923     {
924       if (lp_security() >= SEC_USER) 
925       {
926         if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
927         {
928           DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
929           return bad_password_error(inbuf,outbuf);
930         }
931
932         if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
933         {
934           if (smb_getpwnam(user,True))
935           {
936             DEBUG(1,("Rejecting user '%s': bad password\n", user));
937             return bad_password_error(inbuf,outbuf);
938           }
939         }
940
941         /*
942          * ..else if lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
943          * Then always map to guest account - as done below.
944          */
945       }
946
947       if (*smb_apasswd || !smb_getpwnam(user,True))
948          pstrcpy(user,lp_guestaccount(-1));
949       DEBUG(3,("Registered username %s for guest access\n",user));
950       guest = True;
951     }
952   }
953
954   if (!smb_getpwnam(user,True)) {
955     DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
956     pstrcpy(user,lp_guestaccount(-1));
957     guest = True;
958   }
959
960   if (!strequal(user,lp_guestaccount(-1)) &&
961       lp_servicenumber(user) < 0)      
962   {
963     int homes = lp_servicenumber(HOMES_NAME);
964     char *home = get_user_home_dir(user);
965     if (homes >= 0 && home)
966       lp_add_home(user,homes,home);
967   }
968
969
970   /* it's ok - setup a reply */
971   if (Protocol < PROTOCOL_NT1) {
972     set_message(outbuf,3,0,True);
973   } else {
974     char *p;
975     set_message(outbuf,3,3,True);
976     p = smb_buf(outbuf);
977     pstrcpy(p,"Unix"); p = skip_string(p,1);
978     pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1);
979     pstrcpy(p,global_myworkgroup); p = skip_string(p,1);
980     set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
981     /* perhaps grab OS version here?? */
982   }
983
984   /* Set the correct uid in the outgoing and incoming packets
985      We will use this on future requests to determine which
986      user we should become.
987      */
988   {
989     const struct passwd *pw = smb_getpwnam(user,False);
990     if (!pw) {
991       DEBUG(1,("Username %s is invalid on this system\n",user));
992       return bad_password_error(inbuf,outbuf);
993     }
994     gid = pw->pw_gid;
995     uid = pw->pw_uid;
996   }
997
998   if (guest)
999     SSVAL(outbuf,smb_vwv2,1);
1000
1001   /* register the name and uid as being validated, so further connections
1002      to a uid can get through without a password, on the same VC */
1003   sess_vuid = register_vuid(uid,gid,user,sesssetup_user,domain,guest);
1004  
1005   SSVAL(outbuf,smb_uid,sess_vuid);
1006   SSVAL(inbuf,smb_uid,sess_vuid);
1007
1008   if (!done_sesssetup)
1009     max_send = MIN(max_send,smb_bufsize);
1010
1011   DEBUG(6,("Client requested max send size of %d\n", max_send));
1012
1013   done_sesssetup = True;
1014
1015   return chain_reply(inbuf,outbuf,length,bufsize);
1016 }
1017
1018
1019 /****************************************************************************
1020   reply to a chkpth
1021 ****************************************************************************/
1022 int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1023 {
1024   int outsize = 0;
1025   int mode;
1026   pstring name;
1027   BOOL ok = False;
1028   BOOL bad_path = False;
1029   SMB_STRUCT_STAT st;
1030  
1031   pstrcpy(name,smb_buf(inbuf) + 1);
1032
1033   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
1034
1035   unix_convert(name,conn,0,&bad_path,&st);
1036
1037   mode = SVAL(inbuf,smb_vwv0);
1038
1039   if (check_name(name,conn)) {
1040     if(VALID_STAT(st))
1041       ok = S_ISDIR(st.st_mode);
1042     else
1043       ok = vfs_directory_exist(conn,name,NULL);
1044   }
1045
1046   if (!ok)
1047   {
1048     /* We special case this - as when a Windows machine
1049        is parsing a path is steps through the components
1050        one at a time - if a component fails it expects
1051        ERRbadpath, not ERRbadfile.
1052      */
1053     if(errno == ENOENT)
1054     {
1055       unix_ERR_class = ERRDOS;
1056       unix_ERR_code = ERRbadpath;
1057     }
1058
1059 #if 0
1060     /* Ugly - NT specific hack - maybe not needed ? (JRA) */
1061     if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
1062        (get_remote_arch() == RA_WINNT))
1063     {
1064       unix_ERR_class = ERRDOS;
1065       unix_ERR_code = ERRbaddirectory;
1066     }
1067 #endif
1068
1069     return(UNIXERROR(ERRDOS,ERRbadpath));
1070   }
1071
1072   outsize = set_message(outbuf,0,0,True);
1073
1074   DEBUG(3,("chkpth %s mode=%d\n", name, mode));
1075
1076   return(outsize);
1077 }
1078
1079
1080 /****************************************************************************
1081   reply to a getatr
1082 ****************************************************************************/
1083 int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1084 {
1085   pstring fname;
1086   int outsize = 0;
1087   SMB_STRUCT_STAT sbuf;
1088   BOOL ok = False;
1089   int mode=0;
1090   SMB_OFF_T size=0;
1091   time_t mtime=0;
1092   BOOL bad_path = False;
1093  
1094   pstrcpy(fname,smb_buf(inbuf) + 1);
1095
1096   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1097   
1098   /* if((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && dfs_redirect(fname,conn)) return(dfs_path_error(inbuf,outbuf)); 
1099    */
1100   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1101      under WfWg - weird! */
1102   if (! (*fname))
1103   {
1104     mode = aHIDDEN | aDIR;
1105     if (!CAN_WRITE(conn)) mode |= aRONLY;
1106     size = 0;
1107     mtime = 0;
1108     ok = True;
1109   }
1110   else
1111   {
1112     unix_convert(fname,conn,0,&bad_path,&sbuf);
1113     if (check_name(fname,conn))
1114     {
1115       if (VALID_STAT(sbuf) || dos_stat(fname,&sbuf) == 0)
1116       {
1117         mode = dos_mode(conn,fname,&sbuf);
1118         size = sbuf.st_size;
1119         mtime = sbuf.st_mtime;
1120         if (mode & aDIR)
1121           size = 0;
1122         ok = True;
1123       }
1124       else
1125         DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
1126     }
1127   }
1128   
1129   if (!ok)
1130   {
1131     if((errno == ENOENT) && bad_path)
1132     {
1133       unix_ERR_class = ERRDOS;
1134       unix_ERR_code = ERRbadpath;
1135     }
1136
1137     return(UNIXERROR(ERRDOS,ERRbadfile));
1138   }
1139  
1140   outsize = set_message(outbuf,10,0,True);
1141
1142   SSVAL(outbuf,smb_vwv0,mode);
1143   if(lp_dos_filetime_resolution(SNUM(conn)) )
1144     put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
1145   else
1146     put_dos_date3(outbuf,smb_vwv1,mtime);
1147   SIVAL(outbuf,smb_vwv3,(uint32)size);
1148
1149   if (Protocol >= PROTOCOL_NT1) {
1150     char *p = strrchr(fname,'/');
1151     uint16 flg2 = SVAL(outbuf,smb_flg2);
1152     if (!p) p = fname;
1153     if (!is_8_3(fname, True))
1154       SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1155   }
1156   
1157   DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
1158   
1159   return(outsize);
1160 }
1161
1162
1163 /****************************************************************************
1164   reply to a setatr
1165 ****************************************************************************/
1166 int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1167 {
1168   pstring fname;
1169   int outsize = 0;
1170   BOOL ok=False;
1171   int mode;
1172   time_t mtime;
1173   SMB_STRUCT_STAT st;
1174   BOOL bad_path = False;
1175  
1176   pstrcpy(fname,smb_buf(inbuf) + 1);
1177   unix_convert(fname,conn,0,&bad_path,&st);
1178
1179   mode = SVAL(inbuf,smb_vwv0);
1180   mtime = make_unix_date3(inbuf+smb_vwv1);
1181   
1182   if (VALID_STAT_OF_DIR(st) || vfs_directory_exist(conn, fname, NULL))
1183     mode |= aDIR;
1184   if (check_name(fname,conn))
1185     ok =  (file_chmod(conn,fname,mode,NULL) == 0);
1186   if (ok)
1187     ok = set_filetime(conn,fname,mtime);
1188   
1189   if (!ok)
1190   {
1191     if((errno == ENOENT) && bad_path)
1192     {
1193       unix_ERR_class = ERRDOS;
1194       unix_ERR_code = ERRbadpath;
1195     }
1196
1197     return(UNIXERROR(ERRDOS,ERRnoaccess));
1198   }
1199  
1200   outsize = set_message(outbuf,0,0,True);
1201   
1202   DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
1203   
1204   return(outsize);
1205 }
1206
1207
1208 /****************************************************************************
1209   reply to a dskattr
1210 ****************************************************************************/
1211 int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1212 {
1213   int outsize = 0;
1214   SMB_BIG_UINT dfree,dsize,bsize;
1215   
1216   conn->vfs_ops.disk_free(".",True,&bsize,&dfree,&dsize);
1217   
1218   outsize = set_message(outbuf,5,0,True);
1219   
1220   SSVAL(outbuf,smb_vwv0,dsize);
1221   SSVAL(outbuf,smb_vwv1,bsize/512);
1222   SSVAL(outbuf,smb_vwv2,512);
1223   SSVAL(outbuf,smb_vwv3,dfree);
1224
1225   DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1226
1227   return(outsize);
1228 }
1229
1230
1231 /****************************************************************************
1232   reply to a search
1233   Can be called from SMBsearch, SMBffirst or SMBfunique.
1234 ****************************************************************************/
1235 int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1236 {
1237   pstring mask;
1238   pstring directory;
1239   pstring fname;
1240   SMB_OFF_T size;
1241   int mode;
1242   time_t date;
1243   int dirtype;
1244   int outsize = 0;
1245   int numentries = 0;
1246   BOOL finished = False;
1247   int maxentries;
1248   int i;
1249   char *p;
1250   BOOL ok = False;
1251   int status_len;
1252   char *path;
1253   char status[21];
1254   int dptr_num= -1;
1255   BOOL check_descend = False;
1256   BOOL expect_close = False;
1257   BOOL can_open = True;
1258   BOOL bad_path = False;
1259
1260   *mask = *directory = *fname = 0;
1261
1262   /* If we were called as SMBffirst then we must expect close. */
1263   if(CVAL(inbuf,smb_com) == SMBffirst)
1264     expect_close = True;
1265   
1266   outsize = set_message(outbuf,1,3,True);
1267   maxentries = SVAL(inbuf,smb_vwv0); 
1268   dirtype = SVAL(inbuf,smb_vwv1);
1269   path = smb_buf(inbuf) + 1;
1270   status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
1271
1272   
1273   /* dirtype &= ~aDIR; */
1274   
1275   if (status_len == 0)
1276   {
1277     pstring dir2;
1278
1279     pstrcpy(directory,smb_buf(inbuf)+1);
1280     pstrcpy(dir2,smb_buf(inbuf)+1);
1281     unix_convert(directory,conn,0,&bad_path,NULL);
1282     unix_format(dir2);
1283
1284     if (!check_name(directory,conn))
1285       can_open = False;
1286
1287     p = strrchr(dir2,'/');
1288     if (p == NULL) 
1289     {
1290       pstrcpy(mask,dir2);
1291       *dir2 = 0;
1292     }
1293     else
1294     {
1295       *p = 0;
1296       pstrcpy(mask,p+1);
1297     }
1298
1299     p = strrchr(directory,'/');
1300     if (!p) 
1301       *directory = 0;
1302     else
1303       *p = 0;
1304
1305     if (strlen(directory) == 0)
1306       pstrcpy(directory,"./");
1307     memset((char *)status,'\0',21);
1308     CVAL(status,0) = dirtype;
1309   }
1310   else
1311   {
1312     memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
1313     dirtype = CVAL(status,0) & 0x1F;
1314     conn->dirptr = dptr_fetch(status+12,&dptr_num);      
1315     if (!conn->dirptr)
1316       goto SearchEmpty;
1317     string_set(&conn->dirpath,dptr_path(dptr_num));
1318     fstrcpy(mask, dptr_wcard(dptr_num));
1319   }
1320
1321   if (can_open)
1322   {
1323     p = smb_buf(outbuf) + 3;
1324       
1325     ok = True;
1326      
1327     if (status_len == 0)
1328     {
1329       dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
1330       if (dptr_num < 0)
1331       {
1332         if(dptr_num == -2)
1333         {
1334           if((errno == ENOENT) && bad_path)
1335           {
1336             unix_ERR_class = ERRDOS;
1337             unix_ERR_code = ERRbadpath;
1338           }
1339           return (UNIXERROR(ERRDOS,ERRnofids));
1340         }
1341         return(ERROR(ERRDOS,ERRnofids));
1342       }
1343       dptr_set_wcard(dptr_num, strdup(mask));
1344     }
1345
1346     DEBUG(4,("dptr_num is %d\n",dptr_num));
1347
1348     if (ok)
1349     {
1350       if ((dirtype&0x1F) == aVOLID)
1351       {   
1352         memcpy(p,status,21);
1353         make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
1354         dptr_fill(p+12,dptr_num);
1355         if (dptr_zero(p+12) && (status_len==0))
1356           numentries = 1;
1357         else
1358           numentries = 0;
1359         p += DIR_STRUCT_SIZE;
1360       }
1361       else 
1362       {
1363         DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1364               conn->dirpath,lp_dontdescend(SNUM(conn))));
1365         if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
1366           check_descend = True;
1367
1368         for (i=numentries;(i<maxentries) && !finished;i++)
1369         {
1370           finished = 
1371             !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
1372           if (!finished)
1373           {
1374             memcpy(p,status,21);
1375             make_dir_struct(p,mask,fname,size,mode,date);
1376             dptr_fill(p+12,dptr_num);
1377             numentries++;
1378           }
1379           p += DIR_STRUCT_SIZE;
1380         }
1381       }
1382         } /* if (ok ) */
1383   }
1384
1385
1386   SearchEmpty:
1387
1388   if (numentries == 0 || !ok)
1389   {
1390     CVAL(outbuf,smb_rcls) = ERRDOS;
1391     SSVAL(outbuf,smb_err,ERRnofiles);
1392     dptr_close(&dptr_num);
1393   }
1394
1395   /* If we were called as SMBffirst with smb_search_id == NULL
1396      and no entries were found then return error and close dirptr 
1397      (X/Open spec) */
1398
1399   if(ok && expect_close && numentries == 0 && status_len == 0)
1400   {
1401     CVAL(outbuf,smb_rcls) = ERRDOS;
1402     SSVAL(outbuf,smb_err,ERRnofiles);
1403     /* Also close the dptr - we know it's gone */
1404     dptr_close(&dptr_num);
1405   }
1406
1407   /* If we were called as SMBfunique, then we can close the dirptr now ! */
1408   if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
1409     dptr_close(&dptr_num);
1410
1411   SSVAL(outbuf,smb_vwv0,numentries);
1412   SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1413   CVAL(smb_buf(outbuf),0) = 5;
1414   SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
1415
1416   if (Protocol >= PROTOCOL_NT1) {
1417     uint16 flg2 = SVAL(outbuf,smb_flg2);
1418     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1419   }
1420   
1421   outsize += DIR_STRUCT_SIZE*numentries;
1422   smb_setlen(outbuf,outsize - 4);
1423   
1424   if ((! *directory) && dptr_path(dptr_num))
1425     slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
1426
1427   DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
1428         smb_fn_name(CVAL(inbuf,smb_com)), 
1429         mask, directory, dirtype, numentries, maxentries ) );
1430
1431   return(outsize);
1432 }
1433
1434
1435 /****************************************************************************
1436   reply to a fclose (stop directory search)
1437 ****************************************************************************/
1438 int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1439 {
1440   int outsize = 0;
1441   int status_len;
1442   char *path;
1443   char status[21];
1444   int dptr_num= -2;
1445
1446   outsize = set_message(outbuf,1,0,True);
1447   path = smb_buf(inbuf) + 1;
1448   status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
1449
1450   
1451   if (status_len == 0)
1452     return(ERROR(ERRSRV,ERRsrverror));
1453
1454   memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
1455
1456   if(dptr_fetch(status+12,&dptr_num)) {
1457     /*  Close the dptr - we know it's gone */
1458     dptr_close(&dptr_num);
1459   }
1460
1461   SSVAL(outbuf,smb_vwv0,0);
1462
1463   DEBUG(3,("search close\n"));
1464
1465   return(outsize);
1466 }
1467
1468
1469 /****************************************************************************
1470   reply to an open
1471 ****************************************************************************/
1472
1473 int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1474 {
1475   pstring fname;
1476   int outsize = 0;
1477   int fmode=0;
1478   int share_mode;
1479   SMB_OFF_T size = 0;
1480   time_t mtime=0;
1481   mode_t unixmode;
1482   int rmode=0;
1483   SMB_STRUCT_STAT sbuf;
1484   BOOL bad_path = False;
1485   files_struct *fsp;
1486   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1487  
1488   share_mode = SVAL(inbuf,smb_vwv0);
1489
1490   pstrcpy(fname,smb_buf(inbuf)+1);
1491
1492   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1493
1494   unix_convert(fname,conn,0,&bad_path,NULL);
1495     
1496   unixmode = unix_mode(conn,aARCH,fname);
1497       
1498   fsp = open_file_shared(conn,fname,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1499                    unixmode, oplock_request,&rmode,NULL);
1500
1501   if (!fsp)
1502   {
1503     if((errno == ENOENT) && bad_path)
1504     {
1505       unix_ERR_class = ERRDOS;
1506       unix_ERR_code = ERRbadpath;
1507     }
1508     return(UNIXERROR(ERRDOS,ERRnoaccess));
1509   }
1510
1511   if (fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) {
1512     close_file(fsp,False);
1513     return(ERROR(ERRDOS,ERRnoaccess));
1514   }
1515     
1516   size = sbuf.st_size;
1517   fmode = dos_mode(conn,fname,&sbuf);
1518   mtime = sbuf.st_mtime;
1519
1520   if (fmode & aDIR) {
1521     DEBUG(3,("attempt to open a directory %s\n",fname));
1522     close_file(fsp,False);
1523     return(ERROR(ERRDOS,ERRnoaccess));
1524   }
1525   
1526   outsize = set_message(outbuf,7,0,True);
1527   SSVAL(outbuf,smb_vwv0,fsp->fnum);
1528   SSVAL(outbuf,smb_vwv1,fmode);
1529   if(lp_dos_filetime_resolution(SNUM(conn)) )
1530     put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
1531   else
1532     put_dos_date3(outbuf,smb_vwv2,mtime);
1533   SIVAL(outbuf,smb_vwv4,(uint32)size);
1534   SSVAL(outbuf,smb_vwv6,rmode);
1535
1536   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1537     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1538   }
1539     
1540   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1541     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1542   return(outsize);
1543 }
1544
1545
1546 /****************************************************************************
1547   reply to an open and X
1548 ****************************************************************************/
1549 int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1550 {
1551   pstring fname;
1552   int smb_mode = SVAL(inbuf,smb_vwv3);
1553   int smb_attr = SVAL(inbuf,smb_vwv5);
1554   /* Breakout the oplock request bits so we can set the
1555      reply bits separately. */
1556   BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
1557   BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1558   BOOL oplock_request = ex_oplock_request | core_oplock_request;
1559 #if 0
1560   int open_flags = SVAL(inbuf,smb_vwv2);
1561   int smb_sattr = SVAL(inbuf,smb_vwv4); 
1562   uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
1563 #endif
1564   int smb_ofun = SVAL(inbuf,smb_vwv8);
1565   mode_t unixmode;
1566   SMB_OFF_T size=0;
1567   int fmode=0,mtime=0,rmode=0;
1568   SMB_STRUCT_STAT sbuf;
1569   int smb_action = 0;
1570   BOOL bad_path = False;
1571   files_struct *fsp;
1572
1573   /* If it's an IPC, pass off the pipe handler. */
1574   if (IS_IPC(conn) && lp_nt_pipe_support())
1575     return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
1576
1577   /* XXXX we need to handle passed times, sattr and flags */
1578
1579   pstrcpy(fname,smb_buf(inbuf));
1580
1581   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1582
1583   unix_convert(fname,conn,0,&bad_path,NULL);
1584     
1585   unixmode = unix_mode(conn,smb_attr | aARCH, fname);
1586       
1587   fsp = open_file_shared(conn,fname,smb_mode,smb_ofun,unixmode,
1588                        oplock_request, &rmode,&smb_action);
1589       
1590   if (!fsp)
1591   {
1592     if((errno == ENOENT) && bad_path)
1593     {
1594       unix_ERR_class = ERRDOS;
1595       unix_ERR_code = ERRbadpath;
1596     }
1597     return(UNIXERROR(ERRDOS,ERRnoaccess));
1598   }
1599
1600   if (fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) {
1601     close_file(fsp,False);
1602     return(ERROR(ERRDOS,ERRnoaccess));
1603   }
1604
1605   size = sbuf.st_size;
1606   fmode = dos_mode(conn,fname,&sbuf);
1607   mtime = sbuf.st_mtime;
1608   if (fmode & aDIR) {
1609     close_file(fsp,False);
1610     return(ERROR(ERRDOS,ERRnoaccess));
1611   }
1612
1613   /* If the caller set the extended oplock request bit
1614      and we granted one (by whatever means) - set the
1615      correct bit for extended oplock reply.
1616    */
1617
1618   if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1619     smb_action |= EXTENDED_OPLOCK_GRANTED;
1620   }
1621
1622   if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1623     smb_action |= EXTENDED_OPLOCK_GRANTED;
1624   }
1625
1626   /* If the caller set the core oplock request bit
1627      and we granted one (by whatever means) - set the
1628      correct bit for core oplock reply.
1629    */
1630
1631   if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1632     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1633   }
1634
1635   if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1636     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1637   }
1638
1639   set_message(outbuf,15,0,True);
1640   SSVAL(outbuf,smb_vwv2,fsp->fnum);
1641   SSVAL(outbuf,smb_vwv3,fmode);
1642   if(lp_dos_filetime_resolution(SNUM(conn)) )
1643     put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
1644   else
1645     put_dos_date3(outbuf,smb_vwv4,mtime);
1646   SIVAL(outbuf,smb_vwv6,(uint32)size);
1647   SSVAL(outbuf,smb_vwv8,rmode);
1648   SSVAL(outbuf,smb_vwv11,smb_action);
1649
1650   return chain_reply(inbuf,outbuf,length,bufsize);
1651 }
1652
1653
1654 /****************************************************************************
1655   reply to a SMBulogoffX
1656 ****************************************************************************/
1657 int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1658 {
1659   uint16 vuid = SVAL(inbuf,smb_uid);
1660   user_struct *vuser = get_valid_user_struct(vuid);
1661
1662   if(vuser == 0) {
1663     DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
1664   }
1665
1666   /* in user level security we are supposed to close any files
1667      open by this user */
1668   if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
1669           file_close_user(vuid);
1670   }
1671
1672   invalidate_vuid(vuid);
1673
1674   set_message(outbuf,2,0,True);
1675
1676   DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
1677
1678   return chain_reply(inbuf,outbuf,length,bufsize);
1679 }
1680
1681
1682 /****************************************************************************
1683   reply to a mknew or a create
1684 ****************************************************************************/
1685 int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1686 {
1687   pstring fname;
1688   int com;
1689   int outsize = 0;
1690   int createmode;
1691   mode_t unixmode;
1692   int ofun = 0;
1693   BOOL bad_path = False;
1694   files_struct *fsp;
1695   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1696  
1697   com = SVAL(inbuf,smb_com);
1698
1699   createmode = SVAL(inbuf,smb_vwv0);
1700   pstrcpy(fname,smb_buf(inbuf)+1);
1701
1702   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1703
1704   unix_convert(fname,conn,0,&bad_path,NULL);
1705
1706   if (createmode & aVOLID)
1707     {
1708       DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
1709     }
1710   
1711   unixmode = unix_mode(conn,createmode,fname);
1712   
1713   if(com == SMBmknew)
1714   {
1715     /* We should fail if file exists. */
1716     ofun = FILE_CREATE_IF_NOT_EXIST;
1717   }
1718   else
1719   {
1720     /* SMBcreate - Create if file doesn't exist, truncate if it does. */
1721     ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
1722   }
1723
1724   /* Open file in dos compatibility share mode. */
1725   fsp = open_file_shared(conn,fname,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), 
1726                    ofun, unixmode, oplock_request, NULL, NULL);
1727   
1728   if (!fsp)
1729   {
1730     if((errno == ENOENT) && bad_path) 
1731     {
1732       unix_ERR_class = ERRDOS;
1733       unix_ERR_code = ERRbadpath;
1734     }
1735     return(UNIXERROR(ERRDOS,ERRnoaccess));
1736   }
1737  
1738   outsize = set_message(outbuf,1,0,True);
1739   SSVAL(outbuf,smb_vwv0,fsp->fnum);
1740
1741   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1742     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1743   }
1744  
1745   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1746     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1747  
1748   DEBUG( 2, ( "new file %s\n", fname ) );
1749   DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
1750         fname, fsp->fd, createmode, (int)unixmode ) );
1751
1752   return(outsize);
1753 }
1754
1755
1756 /****************************************************************************
1757   reply to a create temporary file
1758 ****************************************************************************/
1759 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1760 {
1761   pstring fname;
1762   pstring fname2;
1763   int outsize = 0;
1764   int createmode;
1765   mode_t unixmode;
1766   BOOL bad_path = False;
1767   files_struct *fsp;
1768   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1769  
1770   createmode = SVAL(inbuf,smb_vwv0);
1771   pstrcpy(fname,smb_buf(inbuf)+1);
1772   pstrcat(fname,"/TMXXXXXX");
1773
1774   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1775
1776   unix_convert(fname,conn,0,&bad_path,NULL);
1777   
1778   unixmode = unix_mode(conn,createmode,fname);
1779   
1780   pstrcpy(fname2,(char *)smbd_mktemp(fname));
1781
1782   /* Open file in dos compatibility share mode. */
1783   /* We should fail if file exists. */
1784   fsp = open_file_shared(conn,fname2,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), 
1785                    (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unixmode, oplock_request, NULL, NULL);
1786
1787   if (!fsp)
1788   {
1789     if((errno == ENOENT) && bad_path)
1790     {
1791       unix_ERR_class = ERRDOS;
1792       unix_ERR_code = ERRbadpath;
1793     }
1794     return(UNIXERROR(ERRDOS,ERRnoaccess));
1795   }
1796
1797   outsize = set_message(outbuf,1,2 + strlen(fname2),True);
1798   SSVAL(outbuf,smb_vwv0,fsp->fnum);
1799   CVAL(smb_buf(outbuf),0) = 4;
1800   pstrcpy(smb_buf(outbuf) + 1,fname2);
1801
1802   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1803     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1804   }
1805   
1806   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1807     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1808
1809   DEBUG( 2, ( "created temp file %s\n", fname2 ) );
1810   DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
1811         fname2, fsp->fd, createmode, (int)unixmode ) );
1812
1813   return(outsize);
1814 }
1815
1816
1817 /*******************************************************************
1818 check if a user is allowed to delete a file
1819 ********************************************************************/
1820 static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
1821 {
1822   SMB_STRUCT_STAT sbuf;
1823   int fmode;
1824
1825   if (!CAN_WRITE(conn)) return(False);
1826
1827   if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
1828   fmode = dos_mode(conn,fname,&sbuf);
1829   if (fmode & aDIR) return(False);
1830   if (!lp_delete_readonly(SNUM(conn))) {
1831     if (fmode & aRONLY) return(False);
1832   }
1833   if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
1834     return(False);
1835   if (!check_file_sharing(conn,fname,False)) return(False);
1836   return(True);
1837 }
1838
1839 /****************************************************************************
1840  Reply to a unlink
1841 ****************************************************************************/
1842
1843 int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1844 {
1845   int outsize = 0;
1846   pstring name;
1847   int dirtype;
1848   pstring directory;
1849   pstring mask;
1850   char *p;
1851   int count=0;
1852   int error = ERRnoaccess;
1853   BOOL has_wild;
1854   BOOL exists=False;
1855   BOOL bad_path = False;
1856   BOOL rc = True;
1857
1858   *directory = *mask = 0;
1859
1860   dirtype = SVAL(inbuf,smb_vwv0);
1861   
1862   pstrcpy(name,smb_buf(inbuf) + 1);
1863    
1864   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
1865
1866   DEBUG(3,("reply_unlink : %s\n",name));
1867    
1868   rc = unix_convert(name,conn,0,&bad_path,NULL);
1869
1870   p = strrchr(name,'/');
1871   if (!p) {
1872     pstrcpy(directory,"./");
1873     pstrcpy(mask,name);
1874   } else {
1875     *p = 0;
1876     pstrcpy(directory,name);
1877     pstrcpy(mask,p+1);
1878   }
1879
1880   /*
1881    * We should only check the mangled cache
1882    * here if unix_convert failed. This means
1883    * that the path in 'mask' doesn't exist
1884    * on the file system and so we need to look
1885    * for a possible mangle. This patch from
1886    * Tine Smukavec <valentin.smukavec@hermes.si>.
1887    */
1888
1889   if (!rc && is_mangled(mask))
1890     check_mangled_cache( mask );
1891
1892   has_wild = ms_has_wild(mask);
1893
1894   if (!has_wild) {
1895     pstrcat(directory,"/");
1896     pstrcat(directory,mask);
1897     if (can_delete(directory,conn,dirtype) && !dos_unlink(directory))
1898       count++;
1899     if (!count)
1900       exists = vfs_file_exist(conn,directory,NULL);    
1901   } else {
1902     void *dirptr = NULL;
1903     char *dname;
1904
1905     if (check_name(directory,conn))
1906       dirptr = OpenDir(conn, directory, True);
1907
1908     /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
1909        the pattern matches against the long name, otherwise the short name 
1910        We don't implement this yet XXXX
1911        */
1912
1913     if (dirptr)
1914       {
1915         error = ERRbadfile;
1916
1917         if (strequal(mask,"????????.???"))
1918           pstrcpy(mask,"*");
1919
1920         while ((dname = ReadDirName(dirptr)))
1921           {
1922             pstring fname;
1923             pstrcpy(fname,dname);
1924             
1925             if(!mask_match(fname, mask, case_sensitive)) continue;
1926
1927             error = ERRnoaccess;
1928             slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
1929             if (!can_delete(fname,conn,dirtype)) continue;
1930             if (!conn->vfs_ops.unlink(dos_to_unix(fname,False))) count++;
1931             DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
1932           }
1933         CloseDir(dirptr);
1934       }
1935   }
1936   
1937   if (count == 0) {
1938     if (exists)
1939       return(ERROR(ERRDOS,error));
1940     else
1941     {
1942       if((errno == ENOENT) && bad_path)
1943       {
1944         unix_ERR_class = ERRDOS;
1945         unix_ERR_code = ERRbadpath;
1946       }
1947       return(UNIXERROR(ERRDOS,error));
1948     }
1949   }
1950   
1951   outsize = set_message(outbuf,0,0,True);
1952   
1953   return(outsize);
1954 }
1955
1956
1957 /****************************************************************************
1958    reply to a readbraw (core+ protocol)
1959 ****************************************************************************/
1960
1961 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
1962 {
1963   size_t maxcount,mincount;
1964   size_t nread = 0;
1965   SMB_OFF_T startpos;
1966   char *header = outbuf;
1967   ssize_t ret=0;
1968   files_struct *fsp;
1969
1970   /*
1971    * Special check if an oplock break has been issued
1972    * and the readraw request croses on the wire, we must
1973    * return a zero length response here.
1974    */
1975
1976   if(global_oplock_break)
1977   {
1978     _smb_setlen(header,0);
1979     transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
1980     DEBUG(5,("readbraw - oplock break finished\n"));
1981     return -1;
1982   }
1983
1984   fsp = file_fsp(inbuf,smb_vwv0);
1985
1986   if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
1987           /*
1988            * fsp could be NULL here so use the value from the packet. JRA.
1989            */
1990           DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
1991           _smb_setlen(header,0);
1992           transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
1993           return(-1);
1994   }
1995
1996   CHECK_FSP(fsp,conn);
1997
1998   flush_write_cache(fsp, READRAW_FLUSH);
1999
2000   startpos = IVAL(inbuf,smb_vwv1);
2001   if(CVAL(inbuf,smb_wct) == 10) {
2002     /*
2003      * This is a large offset (64 bit) read.
2004      */
2005 #ifdef LARGE_SMB_OFF_T
2006
2007     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
2008
2009 #else /* !LARGE_SMB_OFF_T */
2010
2011     /*
2012      * Ensure we haven't been sent a >32 bit offset.
2013      */
2014
2015     if(IVAL(inbuf,smb_vwv8) != 0) {
2016       DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
2017 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
2018       _smb_setlen(header,0);
2019       transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
2020       return(-1);
2021     }
2022
2023 #endif /* LARGE_SMB_OFF_T */
2024
2025     if(startpos < 0) {
2026       DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
2027             (double)startpos ));
2028           _smb_setlen(header,0);
2029           transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
2030           return(-1);
2031     }      
2032   }
2033   maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
2034   mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
2035
2036   /* ensure we don't overrun the packet size */
2037   maxcount = MIN(65535,maxcount);
2038   maxcount = MAX(mincount,maxcount);
2039
2040   if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK))
2041   {
2042     SMB_OFF_T size = fsp->size;
2043     SMB_OFF_T sizeneeded = startpos + maxcount;
2044             
2045     if (size < sizeneeded)
2046     {
2047       SMB_STRUCT_STAT st;
2048       if (fsp->conn->vfs_ops.fstat(fsp->fd,&st) == 0)
2049         size = st.st_size;
2050       if (!fsp->can_write) 
2051         fsp->size = size;
2052     }
2053
2054     nread = MIN(maxcount,(size - startpos));      
2055   }
2056
2057   if (nread < mincount)
2058     nread = 0;
2059   
2060   DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
2061               fsp->fnum, (double)startpos,
2062               (int)maxcount, (int)mincount, (int)nread ) );
2063   
2064 #if UNSAFE_READRAW
2065   {
2066     BOOL seek_fail = False;
2067     int predict=0;
2068     _smb_setlen(header,nread);
2069
2070 #if USE_READ_PREDICTION
2071     if (!fsp->can_write)
2072       predict = read_predict(fsp, fsp->fd,startpos,header+4,NULL,nread);
2073 #endif /* USE_READ_PREDICTION */
2074
2075     if ((nread-predict) > 0) {
2076       if(conn->vfs_ops.seek(fsp,startpos + predict) == -1) {
2077         DEBUG(0,("reply_readbraw: ERROR: seek_file failed.\n"));
2078         ret = 0;
2079         seek_fail = True;
2080       } 
2081     }
2082
2083     if(!seek_fail)
2084       ret = (ssize_t)vfs_transfer_file(-1, fsp->fd, Client, NULL,
2085                                    (SMB_OFF_T)(nread-predict),header,4+predict, 
2086                                    startpos+predict);
2087   }
2088
2089   if (ret != nread+4)
2090     DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
2091              fsp->fsp_name,startpos,nread,ret));
2092
2093 #else /* UNSAFE_READRAW */
2094   ret = read_file(fsp,header+4,startpos,nread);
2095   if (ret < mincount) ret = 0;
2096
2097   _smb_setlen(header,ret);
2098   transfer_file(0,smbd_server_fd(),0,header,4+ret,0);
2099 #endif /* UNSAFE_READRAW */
2100
2101   DEBUG(5,("readbraw finished\n"));
2102   return -1;
2103 }
2104
2105
2106 /****************************************************************************
2107   reply to a lockread (core+ protocol)
2108 ****************************************************************************/
2109 int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
2110 {
2111   ssize_t nread = -1;
2112   char *data;
2113   int outsize = 0;
2114   SMB_OFF_T startpos;
2115   size_t numtoread;
2116   int eclass;
2117   uint32 ecode;
2118   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2119
2120   CHECK_FSP(fsp,conn);
2121   CHECK_READ(fsp);
2122   CHECK_ERROR(fsp);
2123
2124   numtoread = SVAL(inbuf,smb_vwv1);
2125   startpos = IVAL(inbuf,smb_vwv2);
2126   
2127   outsize = set_message(outbuf,5,3,True);
2128   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
2129   data = smb_buf(outbuf) + 3;
2130  
2131   /*
2132    * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
2133    * protocol request that predates the read/write lock concept. 
2134    * Thus instead of asking for a read lock here we need to ask
2135    * for a write lock. JRA.
2136    */
2137
2138   if(!do_lock( fsp, conn, (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &eclass, &ecode)) {
2139     if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
2140       /*
2141        * A blocking lock was requested. Package up
2142        * this smb into a queued request and push it
2143        * onto the blocking lock queue.
2144        */
2145       if(push_blocking_lock_request(inbuf, length, -1, 0))
2146         return -1;
2147     }
2148     return (ERROR(eclass,ecode));
2149   }
2150
2151   nread = read_file(fsp,data,startpos,numtoread);
2152
2153   if (nread < 0)
2154     return(UNIXERROR(ERRDOS,ERRnoaccess));
2155
2156   outsize += nread;
2157   SSVAL(outbuf,smb_vwv0,nread);
2158   SSVAL(outbuf,smb_vwv5,nread+3);
2159   SSVAL(smb_buf(outbuf),1,nread);
2160
2161   DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
2162             fsp->fnum, (int)numtoread, (int)nread ) );
2163
2164   return(outsize);
2165 }
2166
2167
2168 /****************************************************************************
2169   reply to a read
2170 ****************************************************************************/
2171
2172 int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2173 {
2174   size_t numtoread;
2175   ssize_t nread = 0;
2176   char *data;
2177   SMB_OFF_T startpos;
2178   int outsize = 0;
2179   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2180
2181   CHECK_FSP(fsp,conn);
2182   CHECK_READ(fsp);
2183   CHECK_ERROR(fsp);
2184
2185   numtoread = SVAL(inbuf,smb_vwv1);
2186   startpos = IVAL(inbuf,smb_vwv2);
2187   
2188   outsize = set_message(outbuf,5,3,True);
2189   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
2190   data = smb_buf(outbuf) + 3;
2191   
2192   if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK))
2193     return(ERROR(ERRDOS,ERRlock));      
2194
2195   if (numtoread > 0)
2196     nread = read_file(fsp,data,startpos,numtoread);
2197   
2198   if (nread < 0)
2199     return(UNIXERROR(ERRDOS,ERRnoaccess));
2200   
2201   outsize += nread;
2202   SSVAL(outbuf,smb_vwv0,nread);
2203   SSVAL(outbuf,smb_vwv5,nread+3);
2204   CVAL(smb_buf(outbuf),0) = 1;
2205   SSVAL(smb_buf(outbuf),1,nread);
2206   
2207   DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
2208             fsp->fnum, (int)numtoread, (int)nread ) );
2209
2210   return(outsize);
2211 }
2212
2213
2214 /****************************************************************************
2215   reply to a read and X
2216 ****************************************************************************/
2217 int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
2218 {
2219   files_struct *fsp = file_fsp(inbuf,smb_vwv2);
2220   SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
2221   size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
2222   size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
2223   ssize_t nread = -1;
2224   char *data;
2225
2226   /* If it's an IPC, pass off the pipe handler. */
2227   if (IS_IPC(conn))
2228     return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
2229
2230   CHECK_FSP(fsp,conn);
2231   CHECK_READ(fsp);
2232   CHECK_ERROR(fsp);
2233
2234   set_message(outbuf,12,0,True);
2235   data = smb_buf(outbuf);
2236
2237   if(CVAL(inbuf,smb_wct) == 12) {
2238 #ifdef LARGE_SMB_OFF_T
2239     /*
2240      * This is a large offset (64 bit) read.
2241      */
2242     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
2243
2244 #else /* !LARGE_SMB_OFF_T */
2245
2246     /*
2247      * Ensure we haven't been sent a >32 bit offset.
2248      */
2249
2250     if(IVAL(inbuf,smb_vwv10) != 0) {
2251       DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
2252 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
2253       return(ERROR(ERRDOS,ERRbadaccess));
2254     }
2255
2256 #endif /* LARGE_SMB_OFF_T */
2257
2258   }
2259
2260   if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK))
2261     return(ERROR(ERRDOS,ERRlock));
2262   nread = read_file(fsp,data,startpos,smb_maxcnt);
2263   
2264   if (nread < 0)
2265     return(UNIXERROR(ERRDOS,ERRnoaccess));
2266   
2267   SSVAL(outbuf,smb_vwv5,nread);
2268   SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
2269   SSVAL(smb_buf(outbuf),-2,nread);
2270   
2271   DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
2272               fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) );
2273
2274   return chain_reply(inbuf,outbuf,length,bufsize);
2275 }
2276
2277 /****************************************************************************
2278   reply to a writebraw (core+ or LANMAN1.0 protocol)
2279 ****************************************************************************/
2280
2281 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2282 {
2283   ssize_t nwritten=0;
2284   ssize_t total_written=0;
2285   size_t numtowrite=0;
2286   size_t tcount;
2287   SMB_OFF_T startpos;
2288   char *data=NULL;
2289   BOOL write_through;
2290   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2291   int outsize = 0;
2292
2293   CHECK_FSP(fsp,conn);
2294   CHECK_WRITE(fsp);
2295   CHECK_ERROR(fsp);
2296   
2297   tcount = IVAL(inbuf,smb_vwv1);
2298   startpos = IVAL(inbuf,smb_vwv3);
2299   write_through = BITSETW(inbuf+smb_vwv7,0);
2300
2301   /* We have to deal with slightly different formats depending
2302      on whether we are using the core+ or lanman1.0 protocol */
2303   if(Protocol <= PROTOCOL_COREPLUS) {
2304     numtowrite = SVAL(smb_buf(inbuf),-2);
2305     data = smb_buf(inbuf);
2306   } else {
2307     numtowrite = SVAL(inbuf,smb_vwv10);
2308     data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
2309   }
2310
2311   /* force the error type */
2312   CVAL(inbuf,smb_com) = SMBwritec;
2313   CVAL(outbuf,smb_com) = SMBwritec;
2314
2315   if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK))
2316     return(ERROR(ERRDOS,ERRlock));
2317
2318   if (numtowrite>0)
2319     nwritten = write_file(fsp,data,startpos,numtowrite);
2320   
2321   DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
2322            fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
2323
2324   if (nwritten < numtowrite) 
2325     return(UNIXERROR(ERRHRD,ERRdiskfull));
2326
2327   total_written = nwritten;
2328
2329   /* Return a message to the redirector to tell it
2330      to send more bytes */
2331   CVAL(outbuf,smb_com) = SMBwritebraw;
2332   SSVALS(outbuf,smb_vwv0,-1);
2333   outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
2334   send_smb(smbd_server_fd(),outbuf);
2335   
2336   /* Now read the raw data into the buffer and write it */
2337   if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
2338     exit_server("secondary writebraw failed");
2339   }
2340   
2341   /* Even though this is not an smb message, smb_len
2342      returns the generic length of an smb message */
2343   numtowrite = smb_len(inbuf);
2344
2345   if (tcount > nwritten+numtowrite) {
2346     DEBUG(3,("Client overestimated the write %d %d %d\n",
2347              (int)tcount,(int)nwritten,(int)numtowrite));
2348   }
2349
2350   nwritten = vfs_transfer_file(smbd_server_fd(), NULL, -1, fsp,
2351                                (SMB_OFF_T)numtowrite,NULL,0, 
2352                                startpos+nwritten);
2353   total_written += nwritten;
2354   
2355   /* Set up outbuf to return the correct return */
2356   outsize = set_message(outbuf,1,0,True);
2357   CVAL(outbuf,smb_com) = SMBwritec;
2358   SSVAL(outbuf,smb_vwv0,total_written);
2359
2360   if (nwritten < (ssize_t)numtowrite) {
2361     CVAL(outbuf,smb_rcls) = ERRHRD;
2362     SSVAL(outbuf,smb_err,ERRdiskfull);      
2363   }
2364
2365   if ((lp_syncalways(SNUM(conn)) || write_through) && 
2366       lp_strict_sync(SNUM(conn)))
2367       sync_file(conn,fsp);
2368
2369   DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
2370            fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
2371
2372   /* we won't return a status if write through is not selected - this 
2373      follows what WfWg does */
2374   if (!write_through && total_written==tcount)
2375     return(-1);
2376
2377   return(outsize);
2378 }
2379
2380 /****************************************************************************
2381   reply to a writeunlock (core+)
2382 ****************************************************************************/
2383
2384 int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2385 {
2386   ssize_t nwritten = -1;
2387   size_t numtowrite;
2388   SMB_OFF_T startpos;
2389   char *data;
2390   int eclass;
2391   uint32 ecode;
2392   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2393   int outsize = 0;
2394
2395   CHECK_FSP(fsp,conn);
2396   CHECK_WRITE(fsp);
2397   CHECK_ERROR(fsp);
2398
2399   numtowrite = SVAL(inbuf,smb_vwv1);
2400   startpos = IVAL(inbuf,smb_vwv2);
2401   data = smb_buf(inbuf) + 3;
2402   
2403   if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
2404     return(ERROR(ERRDOS,ERRlock));
2405
2406   /* The special X/Open SMB protocol handling of
2407      zero length writes is *NOT* done for
2408      this call */
2409   if(numtowrite == 0)
2410     nwritten = 0;
2411   else
2412     nwritten = write_file(fsp,data,startpos,numtowrite);
2413   
2414   if (lp_syncalways(SNUM(conn)))
2415       sync_file(conn,fsp);
2416
2417   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2418     return(UNIXERROR(ERRDOS,ERRnoaccess));
2419
2420   if(!do_unlock(fsp, conn, (SMB_BIG_UINT)numtowrite, (SMB_BIG_UINT)startpos, &eclass, &ecode))
2421     return(ERROR(eclass,ecode));
2422
2423   outsize = set_message(outbuf,1,0,True);
2424   
2425   SSVAL(outbuf,smb_vwv0,nwritten);
2426   
2427   DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
2428               fsp->fnum, (int)numtowrite, (int)nwritten ) );
2429
2430   return(outsize);
2431 }
2432
2433 /****************************************************************************
2434   reply to a write
2435 ****************************************************************************/
2436 int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
2437 {
2438   size_t numtowrite;
2439   ssize_t nwritten = -1;
2440   SMB_OFF_T startpos;
2441   char *data;
2442   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2443   int outsize = 0;
2444
2445   /* If it's an IPC, pass off the pipe handler. */
2446   if (IS_IPC(conn))
2447     return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
2448
2449   CHECK_FSP(fsp,conn);
2450   CHECK_WRITE(fsp);
2451   CHECK_ERROR(fsp);
2452
2453   numtowrite = SVAL(inbuf,smb_vwv1);
2454   startpos = IVAL(inbuf,smb_vwv2);
2455   data = smb_buf(inbuf) + 3;
2456   
2457   if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
2458     return(ERROR(ERRDOS,ERRlock));
2459
2460   /* X/Open SMB protocol says that if smb_vwv1 is
2461      zero then the file size should be extended or
2462      truncated to the size given in smb_vwv[2-3] */
2463   if(numtowrite == 0) {
2464       if((nwritten = set_filelen(fsp->fd, (SMB_OFF_T)startpos)) >= 0) /* tpot vfs */
2465       set_filelen_write_cache(fsp, startpos); 
2466   } else
2467     nwritten = write_file(fsp,data,startpos,numtowrite);
2468   
2469   if (lp_syncalways(SNUM(conn)))
2470     sync_file(conn,fsp);
2471
2472   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2473     return(UNIXERROR(ERRDOS,ERRnoaccess));
2474
2475   outsize = set_message(outbuf,1,0,True);
2476   
2477   SSVAL(outbuf,smb_vwv0,nwritten);
2478
2479   if (nwritten < (ssize_t)numtowrite) {
2480     CVAL(outbuf,smb_rcls) = ERRHRD;
2481     SSVAL(outbuf,smb_err,ERRdiskfull);      
2482   }
2483   
2484   DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
2485            fsp->fnum, (int)numtowrite, (int)nwritten));
2486
2487   return(outsize);
2488 }
2489
2490
2491 /****************************************************************************
2492   reply to a write and X
2493 ****************************************************************************/
2494 int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
2495 {
2496   files_struct *fsp = file_fsp(inbuf,smb_vwv2);
2497   SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
2498   size_t numtowrite = SVAL(inbuf,smb_vwv10);
2499   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
2500   ssize_t nwritten = -1;
2501   unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
2502   char *data;
2503
2504   /* If it's an IPC, pass off the pipe handler. */
2505   if (IS_IPC(conn))
2506     return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
2507
2508   CHECK_FSP(fsp,conn);
2509   CHECK_WRITE(fsp);
2510   CHECK_ERROR(fsp);
2511
2512   if(smb_doff > smb_len(inbuf))
2513     return(ERROR(ERRDOS,ERRbadmem));
2514
2515   data = smb_base(inbuf) + smb_doff;
2516
2517   if(CVAL(inbuf,smb_wct) == 14) {
2518 #ifdef LARGE_SMB_OFF_T
2519     /*
2520      * This is a large offset (64 bit) write.
2521      */
2522     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
2523
2524 #else /* !LARGE_SMB_OFF_T */
2525
2526     /*
2527      * Ensure we haven't been sent a >32 bit offset.
2528      */
2529
2530     if(IVAL(inbuf,smb_vwv12) != 0) {
2531       DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
2532 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
2533       return(ERROR(ERRDOS,ERRbadaccess));
2534     }
2535
2536 #endif /* LARGE_SMB_OFF_T */
2537   }
2538
2539   if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
2540     return(ERROR(ERRDOS,ERRlock));
2541
2542   /* X/Open SMB protocol says that, unlike SMBwrite
2543      if the length is zero then NO truncation is
2544      done, just a write of zero. To truncate a file,
2545      use SMBwrite. */
2546   if(numtowrite == 0)
2547     nwritten = 0;
2548   else
2549     nwritten = write_file(fsp,data,startpos,numtowrite);
2550   
2551   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2552     return(UNIXERROR(ERRDOS,ERRnoaccess));
2553
2554   set_message(outbuf,6,0,True);
2555   
2556   SSVAL(outbuf,smb_vwv2,nwritten);
2557   
2558   if (nwritten < (ssize_t)numtowrite) {
2559     CVAL(outbuf,smb_rcls) = ERRHRD;
2560     SSVAL(outbuf,smb_err,ERRdiskfull);      
2561   }
2562
2563   DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
2564            fsp->fnum, (int)numtowrite, (int)nwritten));
2565
2566   if (lp_syncalways(SNUM(conn)) || write_through)
2567     sync_file(conn,fsp);
2568
2569   return chain_reply(inbuf,outbuf,length,bufsize);
2570 }
2571
2572
2573 /****************************************************************************
2574   reply to a lseek
2575 ****************************************************************************/
2576
2577 int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2578 {
2579   SMB_OFF_T startpos;
2580   SMB_OFF_T res= -1;
2581   int mode,umode;
2582   int outsize = 0;
2583   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2584
2585   CHECK_FSP(fsp,conn);
2586   CHECK_ERROR(fsp);
2587
2588   flush_write_cache(fsp, SEEK_FLUSH);
2589
2590   mode = SVAL(inbuf,smb_vwv1) & 3;
2591   startpos = IVALS(inbuf,smb_vwv2);
2592
2593   switch (mode) {
2594     case 0: umode = SEEK_SET; break;
2595     case 1: umode = SEEK_CUR; break;
2596     case 2: umode = SEEK_END; break;
2597     default:
2598       umode = SEEK_SET; break;
2599   }
2600
2601   if((res = conn->vfs_ops.lseek(fsp->fd,startpos,umode)) == -1) {
2602     /*
2603      * Check for the special case where a seek before the start
2604      * of the file sets the offset to zero. Added in the CIFS spec,
2605      * section 4.2.7.
2606      */
2607
2608     if(errno == EINVAL) {
2609       SMB_OFF_T current_pos = startpos;
2610
2611       if(umode == SEEK_CUR) {
2612
2613         if((current_pos = conn->vfs_ops.lseek(fsp->fd,0,SEEK_CUR)) == -1)
2614           return(UNIXERROR(ERRDOS,ERRnoaccess));
2615
2616         current_pos += startpos;
2617
2618       } else if (umode == SEEK_END) {
2619
2620         SMB_STRUCT_STAT sbuf;
2621
2622         if(conn->vfs_ops.fstat(fsp->fd, &sbuf) == -1)
2623           return(UNIXERROR(ERRDOS,ERRnoaccess));
2624
2625         current_pos += sbuf.st_size;
2626       }
2627  
2628       if(current_pos < 0)
2629         res = conn->vfs_ops.lseek(fsp->fd,0,SEEK_SET);
2630     }
2631
2632     if(res == -1)
2633       return(UNIXERROR(ERRDOS,ERRnoaccess));
2634   }
2635
2636   fsp->pos = res;
2637   
2638   outsize = set_message(outbuf,2,0,True);
2639   SIVAL(outbuf,smb_vwv0,res);
2640   
2641   DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
2642            fsp->fnum, (double)startpos, (double)res, mode));
2643
2644   return(outsize);
2645 }
2646
2647 /****************************************************************************
2648   reply to a flush
2649 ****************************************************************************/
2650
2651 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2652 {
2653   int outsize = set_message(outbuf,0,0,True);
2654   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2655
2656   if (fsp) {
2657           CHECK_FSP(fsp,conn);
2658           CHECK_ERROR(fsp);
2659   }
2660
2661   if (!fsp) {
2662           file_sync_all(conn);
2663   } else {
2664                 sync_file(conn,fsp);
2665   }
2666
2667   DEBUG(3,("flush\n"));
2668   return(outsize);
2669 }
2670
2671
2672 /****************************************************************************
2673   reply to a exit
2674 ****************************************************************************/
2675 int reply_exit(connection_struct *conn, 
2676                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2677 {
2678         int outsize = set_message(outbuf,0,0,True);
2679         DEBUG(3,("exit\n"));
2680
2681         return(outsize);
2682 }
2683
2684
2685 /****************************************************************************
2686  Reply to a close - has to deal with closing a directory opened by NT SMB's.
2687 ****************************************************************************/
2688 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
2689                 int dum_buffsize)
2690 {
2691         int outsize = 0;
2692         time_t mtime;
2693         int32 eclass = 0, err = 0;
2694         files_struct *fsp = NULL;
2695
2696         outsize = set_message(outbuf,0,0,True);
2697
2698         /* If it's an IPC, pass off to the pipe handler. */
2699         if (IS_IPC(conn))
2700                 return reply_pipe_close(conn, inbuf,outbuf);
2701
2702         fsp = file_fsp(inbuf,smb_vwv0);
2703
2704         /*
2705          * We can only use CHECK_FSP if we know it's not a directory.
2706          */
2707
2708         if(!fsp || (fsp->conn != conn))
2709                 return(ERROR(ERRDOS,ERRbadfid));
2710
2711         if(HAS_CACHED_ERROR(fsp)) {
2712                 eclass = fsp->wbmpx_ptr->wr_errclass;
2713                 err = fsp->wbmpx_ptr->wr_error;
2714         }
2715
2716         if(fsp->is_directory || fsp->stat_open) {
2717                 /*
2718                  * Special case - close NT SMB directory or stat file
2719                  * handle.
2720                  */
2721                 DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
2722                 close_file(fsp,True);
2723         } else {
2724                 /*
2725                  * Close ordinary file.
2726                  */
2727                 int close_err;
2728
2729                 /*
2730                  * If there was a modify time outstanding,
2731                  * try and set it here.
2732                  */
2733                 if(fsp->pending_modtime)
2734                         set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
2735
2736                 /*
2737                  * Now take care of any time sent in the close.
2738                  */
2739                 mtime = make_unix_date3(inbuf+smb_vwv1);
2740                 
2741                 /* try and set the date */
2742                 set_filetime(conn, fsp->fsp_name,mtime);
2743
2744                 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
2745                          fsp->fd, fsp->fnum,
2746                          conn->num_files_open));
2747  
2748                 /*
2749                  * close_file() returns the unix errno if an error
2750                  * was detected on close - normally this is due to
2751                  * a disk full error. If not then it was probably an I/O error.
2752                  */
2753  
2754                 if((close_err = close_file(fsp,True)) != 0) {
2755                         errno = close_err;
2756                         return (UNIXERROR(ERRHRD,ERRgeneral));
2757                 }
2758         }  
2759
2760         /* We have a cached error */
2761         if(eclass || err)
2762                 return(ERROR(eclass,err));
2763
2764         return(outsize);
2765 }
2766
2767
2768 /****************************************************************************
2769   reply to a writeclose (Core+ protocol)
2770 ****************************************************************************/
2771
2772 int reply_writeclose(connection_struct *conn,
2773                      char *inbuf,char *outbuf, int size, int dum_buffsize)
2774 {
2775         size_t numtowrite;
2776         ssize_t nwritten = -1;
2777         int outsize = 0;
2778         int close_err = 0;
2779         SMB_OFF_T startpos;
2780         char *data;
2781         time_t mtime;
2782         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2783
2784         CHECK_FSP(fsp,conn);
2785         CHECK_WRITE(fsp);
2786         CHECK_ERROR(fsp);
2787
2788         numtowrite = SVAL(inbuf,smb_vwv1);
2789         startpos = IVAL(inbuf,smb_vwv2);
2790         mtime = make_unix_date3(inbuf+smb_vwv4);
2791         data = smb_buf(inbuf) + 1;
2792   
2793         if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
2794                 return(ERROR(ERRDOS,ERRlock));
2795           
2796         nwritten = write_file(fsp,data,startpos,numtowrite);
2797
2798         set_filetime(conn, fsp->fsp_name,mtime);
2799   
2800         close_err = close_file(fsp,True);
2801
2802         DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
2803                  fsp->fnum, (int)numtowrite, (int)nwritten,
2804                  conn->num_files_open));
2805   
2806         if (nwritten <= 0)
2807                 return(UNIXERROR(ERRDOS,ERRnoaccess));
2808  
2809         if(close_err != 0) {
2810                 errno = close_err;
2811                 return(UNIXERROR(ERRHRD,ERRgeneral));
2812         }
2813  
2814         outsize = set_message(outbuf,1,0,True);
2815   
2816         SSVAL(outbuf,smb_vwv0,nwritten);
2817         return(outsize);
2818 }
2819
2820
2821 /****************************************************************************
2822   reply to a lock
2823 ****************************************************************************/
2824 int reply_lock(connection_struct *conn,
2825                char *inbuf,char *outbuf, int length, int dum_buffsize)
2826 {
2827         int outsize = set_message(outbuf,0,0,True);
2828         SMB_BIG_UINT count,offset;
2829         int eclass;
2830         uint32 ecode;
2831         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2832
2833         CHECK_FSP(fsp,conn);
2834         CHECK_ERROR(fsp);
2835
2836         count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
2837         offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
2838
2839         DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
2840                  fsp->fd, fsp->fnum, (double)offset, (double)count));
2841
2842         if (!do_lock(fsp, conn, count, offset, WRITE_LOCK, &eclass, &ecode)) {
2843       if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
2844         /*
2845          * A blocking lock was requested. Package up
2846          * this smb into a queued request and push it
2847          * onto the blocking lock queue.
2848          */
2849         if(push_blocking_lock_request(inbuf, length, -1, 0))
2850           return -1;
2851       }
2852       return (ERROR(eclass,ecode));
2853     }
2854
2855         return(outsize);
2856 }
2857
2858
2859 /****************************************************************************
2860   reply to a unlock
2861 ****************************************************************************/
2862 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2863 {
2864   int outsize = set_message(outbuf,0,0,True);
2865   SMB_BIG_UINT count,offset;
2866   int eclass;
2867   uint32 ecode;
2868   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2869
2870   CHECK_FSP(fsp,conn);
2871   CHECK_ERROR(fsp);
2872
2873   count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
2874   offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
2875
2876   if(!do_unlock(fsp, conn, count, offset, &eclass, &ecode))
2877     return (ERROR(eclass,ecode));
2878
2879   DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
2880         fsp->fd, fsp->fnum, (double)offset, (double)count ) );
2881   
2882   return(outsize);
2883 }
2884
2885
2886 /****************************************************************************
2887   reply to a tdis
2888 ****************************************************************************/
2889 int reply_tdis(connection_struct *conn, 
2890                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2891 {
2892         int outsize = set_message(outbuf,0,0,True);
2893         uint16 vuid;
2894
2895         vuid = SVAL(inbuf,smb_uid);
2896
2897         if (!conn) {
2898                 DEBUG(4,("Invalid connection in tdis\n"));
2899                 return(ERROR(ERRSRV,ERRinvnid));
2900         }
2901
2902         conn->used = False;
2903
2904         close_cnum(conn,vuid);
2905   
2906         return outsize;
2907 }
2908
2909
2910
2911 /****************************************************************************
2912   reply to a echo
2913 ****************************************************************************/
2914 int reply_echo(connection_struct *conn,
2915                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2916 {
2917         int smb_reverb = SVAL(inbuf,smb_vwv0);
2918         int seq_num;
2919         unsigned int data_len = smb_buflen(inbuf);
2920         int outsize = set_message(outbuf,1,data_len,True);
2921
2922         data_len = MIN(data_len, (sizeof(inbuf)-(smb_buf(inbuf)-inbuf)));
2923
2924         /* copy any incoming data back out */
2925         if (data_len > 0)
2926                 memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
2927
2928         if (smb_reverb > 100) {
2929                 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
2930                 smb_reverb = 100;
2931         }
2932
2933         for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
2934                 SSVAL(outbuf,smb_vwv0,seq_num);
2935
2936                 smb_setlen(outbuf,outsize - 4);
2937
2938                 send_smb(smbd_server_fd(),outbuf);
2939         }
2940
2941         DEBUG(3,("echo %d times\n", smb_reverb));
2942
2943         smb_echo_count++;
2944
2945         return -1;
2946 }
2947
2948
2949 /****************************************************************************
2950   reply to a printopen
2951 ****************************************************************************/
2952 int reply_printopen(connection_struct *conn, 
2953                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2954 {
2955         int outsize = 0;
2956         files_struct *fsp;
2957         
2958         if (!CAN_PRINT(conn))
2959                 return(ERROR(ERRDOS,ERRnoaccess));
2960
2961         /* Open for exclusive use, write only. */
2962         fsp = print_fsp_open(conn,"dos.prn");
2963
2964         if (!fsp) {
2965                 return(UNIXERROR(ERRDOS,ERRnoaccess));
2966         }
2967
2968         outsize = set_message(outbuf,1,0,True);
2969         SSVAL(outbuf,smb_vwv0,fsp->fnum);
2970   
2971         DEBUG(3,("openprint fd=%d fnum=%d\n",
2972                  fsp->fd, fsp->fnum));
2973
2974         return(outsize);
2975 }
2976
2977
2978 /****************************************************************************
2979   reply to a printclose
2980 ****************************************************************************/
2981 int reply_printclose(connection_struct *conn,
2982                      char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2983 {
2984         int outsize = set_message(outbuf,0,0,True);
2985         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2986         int close_err = 0;
2987
2988         CHECK_FSP(fsp,conn);
2989         CHECK_ERROR(fsp);
2990
2991         if (!CAN_PRINT(conn))
2992                 return(ERROR(ERRDOS,ERRnoaccess));
2993   
2994         DEBUG(3,("printclose fd=%d fnum=%d\n",
2995                  fsp->fd,fsp->fnum));
2996   
2997         close_err = close_file(fsp,True);
2998
2999         if(close_err != 0) {
3000                 errno = close_err;
3001                 return(UNIXERROR(ERRHRD,ERRgeneral));
3002         }
3003
3004         return(outsize);
3005 }
3006
3007
3008 /****************************************************************************
3009   reply to a printqueue
3010 ****************************************************************************/
3011 int reply_printqueue(connection_struct *conn,
3012                      char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3013 {
3014         int outsize = set_message(outbuf,2,3,True);
3015         int max_count = SVAL(inbuf,smb_vwv0);
3016         int start_index = SVAL(inbuf,smb_vwv1);
3017
3018         /* we used to allow the client to get the cnum wrong, but that
3019            is really quite gross and only worked when there was only
3020            one printer - I think we should now only accept it if they
3021            get it right (tridge) */
3022         if (!CAN_PRINT(conn))
3023                 return(ERROR(ERRDOS,ERRnoaccess));
3024
3025         SSVAL(outbuf,smb_vwv0,0);
3026         SSVAL(outbuf,smb_vwv1,0);
3027         CVAL(smb_buf(outbuf),0) = 1;
3028         SSVAL(smb_buf(outbuf),1,0);
3029   
3030         DEBUG(3,("printqueue start_index=%d max_count=%d\n",
3031                  start_index, max_count));
3032
3033         {
3034                 print_queue_struct *queue = NULL;
3035                 char *p = smb_buf(outbuf) + 3;
3036                 int count = print_queue_status(SNUM(conn), &queue,NULL);
3037                 int num_to_get = ABS(max_count);
3038                 int first = (max_count>0?start_index:start_index+max_count+1);
3039                 int i;
3040
3041                 if (first >= count)
3042                         num_to_get = 0;
3043                 else
3044                         num_to_get = MIN(num_to_get,count-first);
3045     
3046
3047                 for (i=first;i<first+num_to_get;i++) {
3048                         put_dos_date2(p,0,queue[i].time);
3049                         CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
3050                         SSVAL(p,5, queue[i].job);
3051                         SIVAL(p,7,queue[i].size);
3052                         CVAL(p,11) = 0;
3053                         StrnCpy(p+12,queue[i].user,16);
3054                         p += 28;
3055                 }
3056
3057                 if (count > 0) {
3058                         outsize = set_message(outbuf,2,28*count+3,False); 
3059                         SSVAL(outbuf,smb_vwv0,count);
3060                         SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
3061                         CVAL(smb_buf(outbuf),0) = 1;
3062                         SSVAL(smb_buf(outbuf),1,28*count);
3063                 }
3064
3065                 if (queue) free(queue);
3066           
3067                 DEBUG(3,("%d entries returned in queue\n",count));
3068         }
3069   
3070         return(outsize);
3071 }
3072
3073
3074 /****************************************************************************
3075   reply to a printwrite
3076 ****************************************************************************/
3077 int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3078 {
3079   int numtowrite;
3080   int outsize = set_message(outbuf,0,0,True);
3081   char *data;
3082   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3083   
3084   if (!CAN_PRINT(conn))
3085     return(ERROR(ERRDOS,ERRnoaccess));
3086
3087   CHECK_FSP(fsp,conn);
3088   CHECK_WRITE(fsp);
3089   CHECK_ERROR(fsp);
3090
3091   numtowrite = SVAL(smb_buf(inbuf),1);
3092   data = smb_buf(inbuf) + 3;
3093   
3094   if (write_file(fsp,data,-1,numtowrite) != numtowrite)
3095     return(UNIXERROR(ERRDOS,ERRnoaccess));
3096   
3097   DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
3098   
3099   return(outsize);
3100 }
3101
3102
3103 /****************************************************************************
3104   reply to a mkdir
3105 ****************************************************************************/
3106 int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3107 {
3108   pstring directory;
3109   int outsize,ret= -1;
3110   BOOL bad_path = False;
3111  
3112   pstrcpy(directory,smb_buf(inbuf) + 1);
3113   unix_convert(directory,conn,0,&bad_path,NULL);
3114   
3115   if (check_name(directory, conn))
3116     ret = conn->vfs_ops.mkdir(dos_to_unix(directory,False),
3117                               unix_mode(conn,aDIR,directory));
3118   
3119   if (ret < 0)
3120   {
3121     if((errno == ENOENT) && bad_path)
3122     {
3123       unix_ERR_class = ERRDOS;
3124       unix_ERR_code = ERRbadpath;
3125     }
3126     return(UNIXERROR(ERRDOS,ERRnoaccess));
3127   }
3128
3129   outsize = set_message(outbuf,0,0,True);
3130
3131   DEBUG( 3, ( "mkdir %s ret=%d\n", directory, ret ) );
3132
3133   return(outsize);
3134 }
3135
3136 /****************************************************************************
3137 Static function used by reply_rmdir to delete an entire directory
3138 tree recursively.
3139 ****************************************************************************/
3140
3141 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
3142 {
3143   char *dname = NULL;
3144   BOOL ret = False;
3145   void *dirptr = OpenDir(NULL, directory, False);
3146
3147   if(dirptr == NULL)
3148     return True;
3149
3150   while((dname = ReadDirName(dirptr)))
3151   {
3152     pstring fullname;
3153     SMB_STRUCT_STAT st;
3154
3155     if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3156       continue;
3157
3158     /* Construct the full name. */
3159     if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
3160     {
3161       errno = ENOMEM;
3162       ret = True;
3163       break;
3164     }
3165     pstrcpy(fullname, directory);
3166     pstrcat(fullname, "/");
3167     pstrcat(fullname, dname);
3168
3169     if(conn->vfs_ops.lstat(dos_to_unix(fullname,False), &st) != 0)
3170     {
3171       ret = True;
3172       break;
3173     }
3174
3175     if(st.st_mode & S_IFDIR)
3176     {
3177       if(recursive_rmdir(conn, fullname)!=0)
3178       {
3179         ret = True;
3180         break;
3181       }
3182       if(conn->vfs_ops.rmdir(dos_to_unix(fullname,False)) != 0)
3183       {
3184         ret = True;
3185         break;
3186       }
3187     }
3188     else if(conn->vfs_ops.unlink(dos_to_unix(fullname,False)) != 0)
3189     {
3190       ret = True;
3191       break;
3192     }
3193   }
3194   CloseDir(dirptr);
3195   return ret;
3196 }
3197
3198 /****************************************************************************
3199  The internals of the rmdir code - called elsewhere.
3200 ****************************************************************************/
3201
3202 BOOL rmdir_internals(connection_struct *conn, char *directory)
3203 {
3204   BOOL ok;
3205
3206   ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 0);
3207   if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn)))
3208   {
3209     /* 
3210      * Check to see if the only thing in this directory are
3211      * vetoed files/directories. If so then delete them and
3212      * retry. If we fail to delete any of them (and we *don't*
3213      * do a recursive delete) then fail the rmdir.
3214      */
3215     BOOL all_veto_files = True;
3216     char *dname;
3217     void *dirptr = OpenDir(conn, directory, False);
3218
3219     if(dirptr != NULL)
3220     {
3221       int dirpos = TellDir(dirptr);
3222       while ((dname = ReadDirName(dirptr)))
3223       {
3224         if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3225           continue;
3226         if(!IS_VETO_PATH(conn, dname))
3227         {
3228           all_veto_files = False;
3229           break;
3230         }
3231       }
3232       if(all_veto_files)
3233       {
3234         SeekDir(dirptr,dirpos);
3235         while ((dname = ReadDirName(dirptr)))
3236         {
3237           pstring fullname;
3238           SMB_STRUCT_STAT st;
3239
3240           if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3241             continue;
3242
3243           /* Construct the full name. */
3244           if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
3245           {
3246             errno = ENOMEM;
3247             break;
3248           }
3249           pstrcpy(fullname, directory);
3250           pstrcat(fullname, "/");
3251           pstrcat(fullname, dname);
3252                      
3253           if(conn->vfs_ops.lstat(dos_to_unix(fullname, False), &st) != 0)
3254             break;
3255           if(st.st_mode & S_IFDIR)
3256           {
3257             if(lp_recursive_veto_delete(SNUM(conn)))
3258             {
3259               if(recursive_rmdir(conn, fullname) != 0)
3260                 break;
3261             }
3262             if(conn->vfs_ops.rmdir(dos_to_unix(fullname, False)) != 0)
3263               break;
3264           }
3265           else if(conn->vfs_ops.unlink(dos_to_unix(fullname, False)) != 0)
3266             break;
3267         }
3268         CloseDir(dirptr);
3269         /* Retry the rmdir */
3270         ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 0);
3271       }
3272       else
3273         CloseDir(dirptr);
3274     }
3275     else
3276       errno = ENOTEMPTY;
3277   }
3278           
3279   if (!ok)
3280     DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n",
3281           directory,strerror(errno)));
3282
3283   return ok;
3284 }
3285
3286 /****************************************************************************
3287  Reply to a rmdir.
3288 ****************************************************************************/
3289
3290 int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3291 {
3292   pstring directory;
3293   int outsize = 0;
3294   BOOL ok = False;
3295   BOOL bad_path = False;
3296
3297   pstrcpy(directory,smb_buf(inbuf) + 1);
3298
3299   RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
3300
3301   unix_convert(directory,conn, NULL,&bad_path,NULL);
3302   
3303   if (check_name(directory,conn))
3304   {
3305     dptr_closepath(directory,SVAL(inbuf,smb_pid));
3306     ok = rmdir_internals(conn, directory);
3307   }
3308   
3309   if (!ok)
3310   {
3311     if((errno == ENOENT) && bad_path)
3312     {
3313       unix_ERR_class = ERRDOS;
3314       unix_ERR_code = ERRbadpath;
3315     }
3316     return(UNIXERROR(ERRDOS,ERRbadpath));
3317   }
3318  
3319   outsize = set_message(outbuf,0,0,True);
3320   
3321   DEBUG( 3, ( "rmdir %s\n", directory ) );
3322   
3323   return(outsize);
3324 }
3325
3326
3327 /*******************************************************************
3328 resolve wildcards in a filename rename
3329 ********************************************************************/
3330 static BOOL resolve_wildcards(char *name1,char *name2)
3331 {
3332   fstring root1,root2;
3333   fstring ext1,ext2;
3334   char *p,*p2;
3335
3336   name1 = strrchr(name1,'/');
3337   name2 = strrchr(name2,'/');
3338
3339   if (!name1 || !name2) return(False);
3340   
3341   fstrcpy(root1,name1);
3342   fstrcpy(root2,name2);
3343   p = strrchr(root1,'.');
3344   if (p) {
3345     *p = 0;
3346     fstrcpy(ext1,p+1);
3347   } else {
3348     fstrcpy(ext1,"");    
3349   }
3350   p = strrchr(root2,'.');
3351   if (p) {
3352     *p = 0;
3353     fstrcpy(ext2,p+1);
3354   } else {
3355     fstrcpy(ext2,"");    
3356   }
3357
3358   p = root1;
3359   p2 = root2;
3360   while (*p2) {
3361     if (*p2 == '?') {
3362       *p2 = *p;
3363       p2++;
3364     } else {
3365       p2++;
3366     }
3367     if (*p) p++;
3368   }
3369
3370   p = ext1;
3371   p2 = ext2;
3372   while (*p2) {
3373     if (*p2 == '?') {
3374       *p2 = *p;
3375       p2++;
3376     } else {
3377       p2++;
3378     }
3379     if (*p) p++;
3380   }
3381
3382   pstrcpy(name2,root2);
3383   if (ext2[0]) {
3384     pstrcat(name2,".");
3385     pstrcat(name2,ext2);
3386   }
3387
3388   return(True);
3389 }
3390
3391 /*******************************************************************
3392 check if a user is allowed to rename a file
3393 ********************************************************************/
3394 static BOOL can_rename(char *fname,connection_struct *conn)
3395 {
3396   SMB_STRUCT_STAT sbuf;
3397
3398   if (!CAN_WRITE(conn)) return(False);
3399
3400   if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
3401   if (!check_file_sharing(conn,fname,True)) return(False);
3402
3403   return(True);
3404 }
3405
3406 /****************************************************************************
3407  The guts of the rename command, split out so it may be called by the NT SMB
3408  code. 
3409 ****************************************************************************/
3410 int rename_internals(connection_struct *conn, 
3411                      char *inbuf, char *outbuf, char *name, 
3412                      char *newname, BOOL replace_if_exists)
3413 {
3414         pstring directory;
3415         pstring mask;
3416         pstring newname_last_component;
3417         char *p;
3418         BOOL has_wild;
3419         BOOL bad_path1 = False;
3420         BOOL bad_path2 = False;
3421         int count=0;
3422         int error = ERRnoaccess;
3423         BOOL exists=False;
3424         BOOL rc = True;
3425         pstring zdirectory;
3426
3427         *directory = *mask = 0;
3428
3429         rc = unix_convert(name,conn,0,&bad_path1,NULL);
3430         unix_convert(newname,conn,newname_last_component,&bad_path2,NULL);
3431
3432         /*
3433          * Split the old name into directory and last component
3434          * strings. Note that unix_convert may have stripped off a 
3435          * leading ./ from both name and newname if the rename is 
3436          * at the root of the share. We need to make sure either both
3437          * name and newname contain a / character or neither of them do
3438          * as this is checked in resolve_wildcards().
3439          */
3440         
3441         p = strrchr(name,'/');
3442         if (!p) {
3443                 pstrcpy(directory,".");
3444                 pstrcpy(mask,name);
3445         } else {
3446                 *p = 0;
3447                 pstrcpy(directory,name);
3448                 pstrcpy(mask,p+1);
3449                 *p = '/'; /* Replace needed for exceptional test below. */
3450         }
3451
3452         /*
3453          * We should only check the mangled cache
3454          * here if unix_convert failed. This means
3455          * that the path in 'mask' doesn't exist
3456          * on the file system and so we need to look
3457          * for a possible mangle. This patch from
3458          * Tine Smukavec <valentin.smukavec@hermes.si>.
3459          */
3460
3461         if (!rc && is_mangled(mask))
3462                 check_mangled_cache( mask );
3463
3464         has_wild = ms_has_wild(mask);
3465
3466         if (!has_wild) {
3467                 /*
3468                  * No wildcards - just process the one file.
3469                  */
3470                 BOOL is_short_name = is_8_3(name, True);
3471
3472                 /* Add a terminating '/' to the directory name. */
3473                 pstrcat(directory,"/");
3474                 pstrcat(directory,mask);
3475                 
3476                 /* Ensure newname contains a '/' also */
3477                 if(strrchr(newname,'/') == 0) {
3478                         pstring tmpstr;
3479                         
3480                         pstrcpy(tmpstr, "./");
3481                         pstrcat(tmpstr, newname);
3482                         pstrcpy(newname, tmpstr);
3483                 }
3484                 
3485                 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", 
3486                          case_sensitive, case_preserve, short_case_preserve, directory, 
3487                          newname, newname_last_component, is_short_name));
3488
3489                 /*
3490                  * Check for special case with case preserving and not
3491                  * case sensitive, if directory and newname are identical,
3492                  * and the old last component differs from the original
3493                  * last component only by case, then we should allow
3494                  * the rename (user is trying to change the case of the
3495                  * filename).
3496                  */
3497                 if((case_sensitive == False) && 
3498                    (((case_preserve == True) && 
3499                      (is_short_name == False)) || 
3500                     ((short_case_preserve == True) && 
3501                      (is_short_name == True))) &&
3502                    strcsequal(directory, newname)) {
3503                         pstring newname_modified_last_component;
3504
3505                         /*
3506                          * Get the last component of the modified name.
3507                          * Note that we guarantee that newname contains a '/'
3508                          * character above.
3509                          */
3510                         p = strrchr(newname,'/');
3511                         pstrcpy(newname_modified_last_component,p+1);
3512                         
3513                         if(strcsequal(newname_modified_last_component, 
3514                                       newname_last_component) == False) {
3515                                 /*
3516                                  * Replace the modified last component with
3517                                  * the original.
3518                                  */
3519                                 pstrcpy(p+1, newname_last_component);
3520                         }
3521                 }
3522                 
3523                 pstrcpy(zdirectory, dos_to_unix(directory, False));
3524                 if(replace_if_exists) {
3525                         /*
3526                          * NT SMB specific flag - rename can overwrite
3527                          * file with the same name so don't check for
3528                          * vfs_file_exist().
3529                          */
3530                         if(resolve_wildcards(directory,newname) &&
3531                            can_rename(directory,conn) &&
3532                            !conn->vfs_ops.rename(zdirectory,
3533                                                  dos_to_unix(newname,False)))
3534                                 count++;
3535                 } else {
3536                         if (resolve_wildcards(directory,newname) && 
3537                             can_rename(directory,conn) && 
3538                             !vfs_file_exist(conn,newname,NULL) &&
3539                             !conn->vfs_ops.rename(zdirectory,
3540                                                   dos_to_unix(newname,False)))
3541                                 count++;
3542                 }
3543
3544                 DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
3545                          directory,newname));
3546                 
3547                 if (!count) exists = vfs_file_exist(conn,directory,NULL);
3548                 if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
3549                         exists = True;
3550                         error = ERRrename;
3551                 }
3552         } else {
3553                 /*
3554                  * Wildcards - process each file that matches.
3555                  */
3556                 void *dirptr = NULL;
3557                 char *dname;
3558                 pstring destname;
3559                 
3560                 if (check_name(directory,conn))
3561                         dirptr = OpenDir(conn, directory, True);
3562                 
3563                 if (dirptr) {
3564                         error = ERRbadfile;
3565                         
3566                         if (strequal(mask,"????????.???"))
3567                                 pstrcpy(mask,"*");
3568                         
3569                         while ((dname = ReadDirName(dirptr))) {
3570                                 pstring fname;
3571
3572                                 pstrcpy(fname,dname);
3573                                 
3574                                 if(!mask_match(fname, mask, case_sensitive))
3575                                         continue;
3576                                 
3577                                 error = ERRnoaccess;
3578                                 slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
3579                                 if (!can_rename(fname,conn)) {
3580                                         DEBUG(6,("rename %s refused\n", fname));
3581                                         continue;
3582                                 }
3583                                 pstrcpy(destname,newname);
3584                                 
3585                                 if (!resolve_wildcards(fname,destname)) {
3586                                         DEBUG(6,("resolve_wildcards %s %s failed\n", 
3587                                                  fname, destname));
3588                                         continue;
3589                                 }
3590                                 
3591                                 if (!replace_if_exists && 
3592                                     vfs_file_exist(conn,destname, NULL)) {
3593                                         DEBUG(6,("file_exist %s\n", destname));
3594                                         error = 183;
3595                                         continue;
3596                                 }
3597                                 
3598                                 if (!conn->vfs_ops.rename(dos_to_unix(fname,False),
3599                                                           dos_to_unix(destname,False)))
3600                                         count++;
3601                                 DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
3602                         }
3603                         CloseDir(dirptr);
3604                 }
3605         }
3606         
3607         if (count == 0) {
3608                 if (exists)
3609                         return(ERROR(ERRDOS,error));
3610                 else {
3611                         if((errno == ENOENT) && (bad_path1 || bad_path2)) {
3612                                 unix_ERR_class = ERRDOS;
3613                                 unix_ERR_code = ERRbadpath;
3614                         }
3615                         return(UNIXERROR(ERRDOS,error));
3616                 }
3617         }
3618         
3619         return 0;
3620 }
3621
3622 /****************************************************************************
3623  Reply to a mv.
3624 ****************************************************************************/
3625
3626 int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3627 {
3628   int outsize = 0;
3629   pstring name;
3630   pstring newname;
3631
3632   pstrcpy(name,smb_buf(inbuf) + 1);
3633   pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
3634
3635   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
3636   RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
3637
3638   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
3639
3640   outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
3641   if(outsize == 0) 
3642     outsize = set_message(outbuf,0,0,True);
3643   
3644   return(outsize);
3645 }
3646
3647 /*******************************************************************
3648   copy a file as part of a reply_copy
3649   ******************************************************************/
3650
3651 static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
3652                       int count,BOOL target_is_directory, int *err_ret)
3653 {
3654   int Access,action;
3655   SMB_STRUCT_STAT st;
3656   SMB_OFF_T ret=-1;
3657   files_struct *fsp1,*fsp2;
3658   pstring dest;
3659   
3660   *err_ret = 0;
3661
3662   pstrcpy(dest,dest1);
3663   if (target_is_directory) {
3664     char *p = strrchr(src,'/');
3665     if (p) 
3666       p++;
3667     else
3668       p = src;
3669     pstrcat(dest,"/");
3670     pstrcat(dest,p);
3671   }
3672
3673   if (!vfs_file_exist(conn,src,&st))
3674     return(False);
3675
3676   fsp1 = open_file_shared(conn,src,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
3677                    (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
3678
3679   if (!fsp1) {
3680           return(False);
3681   }
3682
3683   if (!target_is_directory && count)
3684     ofun = 1;
3685
3686   fsp2 = open_file_shared(conn,dest,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
3687                    ofun,st.st_mode,0,&Access,&action);
3688
3689   if (!fsp2) {