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