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