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