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