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