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