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