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