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