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