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