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