Makefile:
[samba.git] / source3 / smbd / reply.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Main SMB reply routines
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /*
22    This file handles most of the reply_ calls that the server
23    makes to handle specific protocols
24 */
25
26
27 #include "includes.h"
28 #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_OPEN_FILES;i++)
1494       if ((Files[i].vuid == vuid) && Files[i].open) {
1495         close_file(i,False);
1496       }
1497   }
1498
1499   invalidate_vuid(vuid);
1500
1501   set_message(outbuf,2,0,True);
1502
1503   DEBUG(3,("%s ulogoffX vuid=%d\n",timestring(),vuid));
1504
1505   return chain_reply(inbuf,outbuf,length,bufsize);
1506 }
1507
1508
1509 /****************************************************************************
1510   reply to a mknew or a create
1511 ****************************************************************************/
1512 int reply_mknew(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1513 {
1514   pstring fname;
1515   int cnum,com;
1516   int fnum = -1;
1517   int outsize = 0;
1518   int createmode;
1519   mode_t unixmode;
1520   int ofun = 0;
1521   BOOL bad_path = False;
1522   files_struct *fsp;
1523   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1524  
1525   com = SVAL(inbuf,smb_com);
1526   cnum = SVAL(inbuf,smb_tid);
1527
1528   createmode = SVAL(inbuf,smb_vwv0);
1529   pstrcpy(fname,smb_buf(inbuf)+1);
1530   unix_convert(fname,cnum,0,&bad_path);
1531
1532   if (createmode & aVOLID)
1533     {
1534       DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
1535     }
1536   
1537   unixmode = unix_mode(cnum,createmode);
1538   
1539   fnum = find_free_file();
1540   if (fnum < 0)
1541     return(ERROR(ERRSRV,ERRnofids));
1542
1543   if (!check_name(fname,cnum))
1544   {
1545     if((errno == ENOENT) && bad_path)
1546     {
1547       unix_ERR_class = ERRDOS;
1548       unix_ERR_code = ERRbadpath;
1549     }
1550     Files[fnum].reserved = False;
1551     return(UNIXERROR(ERRDOS,ERRnoaccess));
1552   }
1553
1554   if(com == SMBmknew)
1555   {
1556     /* We should fail if file exists. */
1557     ofun = 0x10;
1558   }
1559   else
1560   {
1561     /* SMBcreate - Create if file doesn't exist, truncate if it does. */
1562     ofun = 0x12;
1563   }
1564
1565   /* Open file in dos compatibility share mode. */
1566   open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode, 
1567                    oplock_request, NULL, NULL);
1568   
1569   fsp = &Files[fnum];
1570
1571   if (!fsp->open)
1572   {
1573     if((errno == ENOENT) && bad_path) 
1574     {
1575       unix_ERR_class = ERRDOS;
1576       unix_ERR_code = ERRbadpath;
1577     }
1578     Files[fnum].reserved = False;
1579     return(UNIXERROR(ERRDOS,ERRnoaccess));
1580   }
1581  
1582   outsize = set_message(outbuf,1,0,True);
1583   SSVAL(outbuf,smb_vwv0,fnum);
1584
1585   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
1586     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1587   }
1588  
1589   if(fsp->granted_oplock)
1590     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1591  
1592   DEBUG(2,("new file %s\n",fname));
1593   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));
1594   
1595   return(outsize);
1596 }
1597
1598
1599 /****************************************************************************
1600   reply to a create temporary file
1601 ****************************************************************************/
1602 int reply_ctemp(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1603 {
1604   pstring fname;
1605   pstring fname2;
1606   int cnum;
1607   int fnum = -1;
1608   int outsize = 0;
1609   int createmode;
1610   mode_t unixmode;
1611   BOOL bad_path = False;
1612   files_struct *fsp;
1613   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1614  
1615   cnum = SVAL(inbuf,smb_tid);
1616   createmode = SVAL(inbuf,smb_vwv0);
1617   pstrcpy(fname,smb_buf(inbuf)+1);
1618   pstrcat(fname,"/TMXXXXXX");
1619   unix_convert(fname,cnum,0,&bad_path);
1620   
1621   unixmode = unix_mode(cnum,createmode);
1622   
1623   fnum = find_free_file();
1624   if (fnum < 0)
1625     return(ERROR(ERRSRV,ERRnofids));
1626
1627   if (!check_name(fname,cnum))
1628   {
1629     if((errno == ENOENT) && bad_path)
1630     {
1631       unix_ERR_class = ERRDOS;
1632       unix_ERR_code = ERRbadpath;
1633     }
1634     Files[fnum].reserved = False;
1635     return(UNIXERROR(ERRDOS,ERRnoaccess));
1636   }
1637
1638   pstrcpy(fname2,(char *)mktemp(fname));
1639
1640   /* Open file in dos compatibility share mode. */
1641   /* We should fail if file exists. */
1642   open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode, 
1643                    oplock_request, NULL, NULL);
1644
1645   fsp = &Files[fnum];
1646
1647   if (!fsp->open)
1648   {
1649     if((errno == ENOENT) && bad_path)
1650     {
1651       unix_ERR_class = ERRDOS;
1652       unix_ERR_code = ERRbadpath;
1653     }
1654     Files[fnum].reserved = False;
1655     return(UNIXERROR(ERRDOS,ERRnoaccess));
1656   }
1657
1658   outsize = set_message(outbuf,1,2 + strlen(fname2),True);
1659   SSVAL(outbuf,smb_vwv0,fnum);
1660   CVAL(smb_buf(outbuf),0) = 4;
1661   pstrcpy(smb_buf(outbuf) + 1,fname2);
1662
1663   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
1664     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1665   }
1666   
1667   if(fsp->granted_oplock)
1668     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1669
1670   DEBUG(2,("created temp file %s\n",fname2));
1671   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));
1672   
1673   return(outsize);
1674 }
1675
1676
1677 /*******************************************************************
1678 check if a user is allowed to delete a file
1679 ********************************************************************/
1680 static BOOL can_delete(char *fname,int cnum,int dirtype)
1681 {
1682   struct stat sbuf;
1683   int fmode;
1684
1685   if (!CAN_WRITE(cnum)) return(False);
1686
1687   if (sys_lstat(fname,&sbuf) != 0) return(False);
1688   fmode = dos_mode(cnum,fname,&sbuf);
1689   if (fmode & aDIR) return(False);
1690   if (!lp_delete_readonly(SNUM(cnum))) {
1691     if (fmode & aRONLY) return(False);
1692   }
1693   if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
1694     return(False);
1695   if (!check_file_sharing(cnum,fname,False)) return(False);
1696   return(True);
1697 }
1698
1699 /****************************************************************************
1700   reply to a unlink
1701 ****************************************************************************/
1702 int reply_unlink(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1703 {
1704   int outsize = 0;
1705   pstring name;
1706   int cnum;
1707   int dirtype;
1708   pstring directory;
1709   pstring mask;
1710   char *p;
1711   int count=0;
1712   int error = ERRnoaccess;
1713   BOOL has_wild;
1714   BOOL exists=False;
1715   BOOL bad_path = False;
1716
1717   *directory = *mask = 0;
1718
1719   cnum = SVAL(inbuf,smb_tid);
1720   dirtype = SVAL(inbuf,smb_vwv0);
1721   
1722   pstrcpy(name,smb_buf(inbuf) + 1);
1723    
1724   DEBUG(3,("reply_unlink : %s\n",name));
1725    
1726   unix_convert(name,cnum,0,&bad_path);
1727
1728   p = strrchr(name,'/');
1729   if (!p) {
1730     pstrcpy(directory,"./");
1731     pstrcpy(mask,name);
1732   } else {
1733     *p = 0;
1734     pstrcpy(directory,name);
1735     pstrcpy(mask,p+1);
1736   }
1737
1738   if (is_mangled(mask))
1739     check_mangled_cache( mask );
1740
1741   has_wild = strchr(mask,'*') || strchr(mask,'?');
1742
1743   if (!has_wild) {
1744     pstrcat(directory,"/");
1745     pstrcat(directory,mask);
1746     if (can_delete(directory,cnum,dirtype) && !sys_unlink(directory)) count++;
1747     if (!count) exists = file_exist(directory,NULL);    
1748   } else {
1749     void *dirptr = NULL;
1750     char *dname;
1751
1752     if (check_name(directory,cnum))
1753       dirptr = OpenDir(cnum, directory, True);
1754
1755     /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
1756        the pattern matches against the long name, otherwise the short name 
1757        We don't implement this yet XXXX
1758        */
1759
1760     if (dirptr)
1761       {
1762         error = ERRbadfile;
1763
1764         if (strequal(mask,"????????.???"))
1765           pstrcpy(mask,"*");
1766
1767         while ((dname = ReadDirName(dirptr)))
1768           {
1769             pstring fname;
1770             pstrcpy(fname,dname);
1771             
1772             if(!mask_match(fname, mask, case_sensitive, False)) continue;
1773
1774             error = ERRnoaccess;
1775             slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
1776             if (!can_delete(fname,cnum,dirtype)) continue;
1777             if (!sys_unlink(fname)) count++;
1778             DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
1779           }
1780         CloseDir(dirptr);
1781       }
1782   }
1783   
1784   if (count == 0) {
1785     if (exists)
1786       return(ERROR(ERRDOS,error));
1787     else
1788     {
1789       if((errno == ENOENT) && bad_path)
1790       {
1791         unix_ERR_class = ERRDOS;
1792         unix_ERR_code = ERRbadpath;
1793       }
1794       return(UNIXERROR(ERRDOS,error));
1795     }
1796   }
1797   
1798   outsize = set_message(outbuf,0,0,True);
1799   
1800   return(outsize);
1801 }
1802
1803
1804 /****************************************************************************
1805    reply to a readbraw (core+ protocol)
1806 ****************************************************************************/
1807 int reply_readbraw(char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
1808 {
1809   int cnum,maxcount,mincount,fnum;
1810   int nread = 0;
1811   uint32 startpos;
1812   char *header = outbuf;
1813   int ret=0;
1814   int fd;
1815   char *fname;
1816
1817   /*
1818    * Special check if an oplock break has been issued
1819    * and the readraw request croses on the wire, we must
1820    * return a zero length response here.
1821    */
1822
1823   if(global_oplock_break)
1824   {
1825     _smb_setlen(header,0);
1826     transfer_file(0,Client,0,header,4,0);
1827     DEBUG(5,("readbraw - oplock break finished\n"));
1828     return -1;
1829   }
1830
1831   cnum = SVAL(inbuf,smb_tid);
1832   fnum = GETFNUM(inbuf,smb_vwv0);
1833
1834   startpos = IVAL(inbuf,smb_vwv1);
1835   maxcount = SVAL(inbuf,smb_vwv3);
1836   mincount = SVAL(inbuf,smb_vwv4);
1837
1838   /* ensure we don't overrun the packet size */
1839   maxcount = MIN(65535,maxcount);
1840   maxcount = MAX(mincount,maxcount);
1841
1842   if (!FNUM_OK(fnum,cnum) || !Files[fnum].can_read)
1843     {
1844       DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fnum));
1845       _smb_setlen(header,0);
1846       transfer_file(0,Client,0,header,4,0);
1847       return(-1);
1848     }
1849   else
1850     {
1851       fd = Files[fnum].fd_ptr->fd;
1852       fname = Files[fnum].name;
1853     }
1854
1855
1856   if (!is_locked(fnum,cnum,maxcount,startpos))
1857     {
1858       int size = Files[fnum].size;
1859       int sizeneeded = startpos + maxcount;
1860             
1861       if (size < sizeneeded) {
1862         struct stat st;
1863         if (fstat(Files[fnum].fd_ptr->fd,&st) == 0)
1864           size = st.st_size;
1865         if (!Files[fnum].can_write) 
1866           Files[fnum].size = size;
1867       }
1868
1869       nread = MIN(maxcount,(int)(size - startpos));       
1870     }
1871
1872   if (nread < mincount)
1873     nread = 0;
1874   
1875   DEBUG(3,("%s readbraw fnum=%d cnum=%d start=%d max=%d min=%d nread=%d\n",
1876            timestring(),
1877            fnum,cnum,startpos,
1878            maxcount,mincount,nread));
1879   
1880 #if UNSAFE_READRAW
1881   {
1882     int predict=0;
1883     _smb_setlen(header,nread);
1884
1885 #if USE_READ_PREDICTION
1886     if (!Files[fnum].can_write)
1887       predict = read_predict(fd,startpos,header+4,NULL,nread);
1888 #endif
1889
1890     if ((nread-predict) > 0)
1891       seek_file(fnum,startpos + predict);
1892     
1893     ret = transfer_file(fd,Client,nread-predict,header,4+predict,
1894                         startpos+predict);
1895   }
1896
1897   if (ret != nread+4)
1898     DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
1899              fname,startpos,nread,ret));
1900
1901 #else
1902   ret = read_file(fnum,header+4,startpos,nread);
1903   if (ret < mincount) ret = 0;
1904
1905   _smb_setlen(header,ret);
1906   transfer_file(0,Client,0,header,4+ret,0);
1907 #endif
1908
1909   DEBUG(5,("readbraw finished\n"));
1910   return -1;
1911 }
1912
1913
1914 /****************************************************************************
1915   reply to a lockread (core+ protocol)
1916 ****************************************************************************/
1917 int reply_lockread(char *inbuf,char *outbuf, int dum_size, int dum_buffsiz)
1918 {
1919   int cnum,fnum;
1920   int nread = -1;
1921   char *data;
1922   int outsize = 0;
1923   uint32 startpos, numtoread;
1924   int eclass;
1925   uint32 ecode;
1926   
1927   cnum = SVAL(inbuf,smb_tid);
1928   fnum = GETFNUM(inbuf,smb_vwv0);
1929
1930   CHECK_FNUM(fnum,cnum);
1931   CHECK_READ(fnum);
1932   CHECK_ERROR(fnum);
1933
1934   numtoread = SVAL(inbuf,smb_vwv1);
1935   startpos = IVAL(inbuf,smb_vwv2);
1936   
1937   outsize = set_message(outbuf,5,3,True);
1938   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1939   data = smb_buf(outbuf) + 3;
1940   
1941   if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
1942     return (ERROR(eclass,ecode));
1943
1944   nread = read_file(fnum,data,startpos,numtoread);
1945   
1946   if (nread < 0)
1947     return(UNIXERROR(ERRDOS,ERRnoaccess));
1948   
1949   outsize += nread;
1950   SSVAL(outbuf,smb_vwv0,nread);
1951   SSVAL(outbuf,smb_vwv5,nread+3);
1952   SSVAL(smb_buf(outbuf),1,nread);
1953   
1954   DEBUG(3,("%s lockread fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
1955   
1956   return(outsize);
1957 }
1958
1959
1960 /****************************************************************************
1961   reply to a read
1962 ****************************************************************************/
1963 int reply_read(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1964 {
1965   int cnum,numtoread,fnum;
1966   int nread = 0;
1967   char *data;
1968   uint32 startpos;
1969   int outsize = 0;
1970   
1971   cnum = SVAL(inbuf,smb_tid);
1972   fnum = GETFNUM(inbuf,smb_vwv0);
1973
1974   CHECK_FNUM(fnum,cnum);
1975   CHECK_READ(fnum);
1976   CHECK_ERROR(fnum);
1977
1978   numtoread = SVAL(inbuf,smb_vwv1);
1979   startpos = IVAL(inbuf,smb_vwv2);
1980   
1981   outsize = set_message(outbuf,5,3,True);
1982   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1983   data = smb_buf(outbuf) + 3;
1984   
1985   if (is_locked(fnum,cnum,numtoread,startpos))
1986     return(ERROR(ERRDOS,ERRlock));      
1987
1988   if (numtoread > 0)
1989     nread = read_file(fnum,data,startpos,numtoread);
1990   
1991   if (nread < 0)
1992     return(UNIXERROR(ERRDOS,ERRnoaccess));
1993   
1994   outsize += nread;
1995   SSVAL(outbuf,smb_vwv0,nread);
1996   SSVAL(outbuf,smb_vwv5,nread+3);
1997   CVAL(smb_buf(outbuf),0) = 1;
1998   SSVAL(smb_buf(outbuf),1,nread);
1999   
2000   DEBUG(3,("%s read fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
2001   
2002   return(outsize);
2003 }
2004
2005
2006 /****************************************************************************
2007   reply to a read and X
2008 ****************************************************************************/
2009 int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
2010 {
2011   int fnum = GETFNUM(inbuf,smb_vwv2);
2012   uint32 smb_offs = IVAL(inbuf,smb_vwv3);
2013   int smb_maxcnt = SVAL(inbuf,smb_vwv5);
2014   int smb_mincnt = SVAL(inbuf,smb_vwv6);
2015   int cnum;
2016   int nread = -1;
2017   char *data;
2018   BOOL ok = False;
2019
2020   cnum = SVAL(inbuf,smb_tid);
2021
2022   /* If it's an IPC, pass off the pipe handler. */
2023   if (IS_IPC(cnum))
2024     return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
2025
2026   CHECK_FNUM(fnum,cnum);
2027   CHECK_READ(fnum);
2028   CHECK_ERROR(fnum);
2029
2030   set_message(outbuf,12,0,True);
2031   data = smb_buf(outbuf);
2032
2033   if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
2034     return(ERROR(ERRDOS,ERRlock));
2035   nread = read_file(fnum,data,smb_offs,smb_maxcnt);
2036   ok = True;
2037   
2038   if (nread < 0)
2039     return(UNIXERROR(ERRDOS,ERRnoaccess));
2040   
2041   SSVAL(outbuf,smb_vwv5,nread);
2042   SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
2043   SSVAL(smb_buf(outbuf),-2,nread);
2044   
2045   DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d\n",
2046         timestring(),fnum,cnum,
2047         smb_mincnt,smb_maxcnt,nread));
2048
2049   chain_fnum = fnum;
2050
2051   return chain_reply(inbuf,outbuf,length,bufsize);
2052 }
2053
2054
2055 /****************************************************************************
2056   reply to a writebraw (core+ or LANMAN1.0 protocol)
2057 ****************************************************************************/
2058 int reply_writebraw(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2059 {
2060   int nwritten=0;
2061   int total_written=0;
2062   int numtowrite=0;
2063   int cnum,fnum;
2064   int outsize = 0;
2065   long startpos;
2066   char *data=NULL;
2067   BOOL write_through;
2068   int tcount;
2069
2070   cnum = SVAL(inbuf,smb_tid);
2071   fnum = GETFNUM(inbuf,smb_vwv0);
2072
2073   CHECK_FNUM(fnum,cnum);
2074   CHECK_WRITE(fnum);
2075   CHECK_ERROR(fnum);
2076   
2077   tcount = IVAL(inbuf,smb_vwv1);
2078   startpos = IVAL(inbuf,smb_vwv3);
2079   write_through = BITSETW(inbuf+smb_vwv7,0);
2080
2081   /* We have to deal with slightly different formats depending
2082      on whether we are using the core+ or lanman1.0 protocol */
2083   if(Protocol <= PROTOCOL_COREPLUS) {
2084     numtowrite = SVAL(smb_buf(inbuf),-2);
2085     data = smb_buf(inbuf);
2086   } else {
2087     numtowrite = SVAL(inbuf,smb_vwv10);
2088     data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
2089   }
2090
2091   /* force the error type */
2092   CVAL(inbuf,smb_com) = SMBwritec;
2093   CVAL(outbuf,smb_com) = SMBwritec;
2094
2095   if (is_locked(fnum,cnum,tcount,startpos))
2096     return(ERROR(ERRDOS,ERRlock));
2097
2098   if (seek_file(fnum,startpos) != startpos)
2099     DEBUG(0,("couldn't seek to %d in writebraw\n",startpos));
2100
2101   if (numtowrite>0)
2102     nwritten = write_file(fnum,data,numtowrite);
2103   
2104   DEBUG(3,("%s writebraw1 fnum=%d cnum=%d start=%d num=%d wrote=%d sync=%d\n",
2105            timestring(),fnum,cnum,startpos,numtowrite,nwritten,write_through));
2106
2107   if (nwritten < numtowrite) 
2108     return(UNIXERROR(ERRHRD,ERRdiskfull));
2109
2110   total_written = nwritten;
2111
2112   /* Return a message to the redirector to tell it
2113      to send more bytes */
2114   CVAL(outbuf,smb_com) = SMBwritebraw;
2115   SSVALS(outbuf,smb_vwv0,-1);
2116   outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
2117   send_smb(Client,outbuf);
2118   
2119   /* Now read the raw data into the buffer and write it */
2120   if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
2121     exit_server("secondary writebraw failed");
2122   }
2123   
2124   /* Even though this is not an smb message, smb_len
2125      returns the generic length of an smb message */
2126   numtowrite = smb_len(inbuf);
2127
2128   if (tcount > nwritten+numtowrite) {
2129     DEBUG(3,("Client overestimated the write %d %d %d\n",
2130              tcount,nwritten,numtowrite));
2131   }
2132
2133   nwritten = transfer_file(Client,Files[fnum].fd_ptr->fd,numtowrite,NULL,0,
2134                            startpos+nwritten);
2135   total_written += nwritten;
2136   
2137   /* Set up outbuf to return the correct return */
2138   outsize = set_message(outbuf,1,0,True);
2139   CVAL(outbuf,smb_com) = SMBwritec;
2140   SSVAL(outbuf,smb_vwv0,total_written);
2141
2142   if (nwritten < numtowrite) {
2143     CVAL(outbuf,smb_rcls) = ERRHRD;
2144     SSVAL(outbuf,smb_err,ERRdiskfull);      
2145   }
2146
2147   if (lp_syncalways(SNUM(cnum)) || write_through)
2148     sync_file(fnum);
2149
2150   DEBUG(3,("%s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d\n",
2151            timestring(),fnum,cnum,startpos,numtowrite,total_written));
2152
2153   /* we won't return a status if write through is not selected - this 
2154      follows what WfWg does */
2155   if (!write_through && total_written==tcount)
2156     return(-1);
2157
2158   return(outsize);
2159 }
2160
2161
2162 /****************************************************************************
2163   reply to a writeunlock (core+)
2164 ****************************************************************************/
2165 int reply_writeunlock(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2166 {
2167   int cnum,fnum;
2168   int nwritten = -1;
2169   int outsize = 0;
2170   char *data;
2171   uint32 numtowrite,startpos;
2172   int eclass;
2173   uint32 ecode;
2174   
2175   cnum = SVAL(inbuf,smb_tid);
2176   fnum = GETFNUM(inbuf,smb_vwv0);
2177
2178   CHECK_FNUM(fnum,cnum);
2179   CHECK_WRITE(fnum);
2180   CHECK_ERROR(fnum);
2181
2182   numtowrite = SVAL(inbuf,smb_vwv1);
2183   startpos = IVAL(inbuf,smb_vwv2);
2184   data = smb_buf(inbuf) + 3;
2185   
2186   if (is_locked(fnum,cnum,numtowrite,startpos))
2187     return(ERROR(ERRDOS,ERRlock));
2188
2189   seek_file(fnum,startpos);
2190
2191   /* The special X/Open SMB protocol handling of
2192      zero length writes is *NOT* done for
2193      this call */
2194   if(numtowrite == 0)
2195     nwritten = 0;
2196   else
2197     nwritten = write_file(fnum,data,numtowrite);
2198   
2199   if (lp_syncalways(SNUM(cnum)))
2200     sync_file(fnum);
2201
2202   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2203     return(UNIXERROR(ERRDOS,ERRnoaccess));
2204
2205   if(!do_unlock(fnum, cnum, numtowrite, startpos, &eclass, &ecode))
2206     return(ERROR(eclass,ecode));
2207
2208   outsize = set_message(outbuf,1,0,True);
2209   
2210   SSVAL(outbuf,smb_vwv0,nwritten);
2211   
2212   DEBUG(3,("%s writeunlock fnum=%d cnum=%d num=%d wrote=%d\n",
2213            timestring(),fnum,cnum,numtowrite,nwritten));
2214   
2215   return(outsize);
2216 }
2217
2218
2219 /****************************************************************************
2220   reply to a write
2221 ****************************************************************************/
2222 int reply_write(char *inbuf,char *outbuf,int dum_size,int dum_buffsize)
2223 {
2224   int cnum,numtowrite,fnum;
2225   int nwritten = -1;
2226   int outsize = 0;
2227   int startpos;
2228   char *data;
2229
2230   cnum = SVAL(inbuf,smb_tid);
2231   fnum = GETFNUM(inbuf,smb_vwv0);
2232
2233   CHECK_FNUM(fnum,cnum);
2234   CHECK_WRITE(fnum);
2235   CHECK_ERROR(fnum);
2236
2237   numtowrite = SVAL(inbuf,smb_vwv1);
2238   startpos = IVAL(inbuf,smb_vwv2);
2239   data = smb_buf(inbuf) + 3;
2240   
2241   if (is_locked(fnum,cnum,numtowrite,startpos))
2242     return(ERROR(ERRDOS,ERRlock));
2243
2244   seek_file(fnum,startpos);
2245
2246   /* X/Open SMB protocol says that if smb_vwv1 is
2247      zero then the file size should be extended or
2248      truncated to the size given in smb_vwv[2-3] */
2249   if(numtowrite == 0)
2250     nwritten = set_filelen(Files[fnum].fd_ptr->fd, startpos);
2251   else
2252     nwritten = write_file(fnum,data,numtowrite);
2253   
2254   if (lp_syncalways(SNUM(cnum)))
2255     sync_file(fnum);
2256
2257   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2258     return(UNIXERROR(ERRDOS,ERRnoaccess));
2259
2260   outsize = set_message(outbuf,1,0,True);
2261   
2262   SSVAL(outbuf,smb_vwv0,nwritten);
2263
2264   if (nwritten < numtowrite) {
2265     CVAL(outbuf,smb_rcls) = ERRHRD;
2266     SSVAL(outbuf,smb_err,ERRdiskfull);      
2267   }
2268   
2269   DEBUG(3,("%s write fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,numtowrite,nwritten));
2270   
2271   return(outsize);
2272 }
2273
2274
2275 /****************************************************************************
2276   reply to a write and X
2277 ****************************************************************************/
2278 int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
2279 {
2280   int fnum = GETFNUM(inbuf,smb_vwv2);
2281   uint32 smb_offs = IVAL(inbuf,smb_vwv3);
2282   int smb_dsize = SVAL(inbuf,smb_vwv10);
2283   int smb_doff = SVAL(inbuf,smb_vwv11);
2284   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
2285   int cnum;
2286   int nwritten = -1;
2287   char *data;
2288
2289   cnum = SVAL(inbuf,smb_tid);
2290
2291   CHECK_FNUM(fnum,cnum);
2292   CHECK_WRITE(fnum);
2293   CHECK_ERROR(fnum);
2294
2295   data = smb_base(inbuf) + smb_doff;
2296
2297   if (is_locked(fnum,cnum,smb_dsize,smb_offs))
2298     return(ERROR(ERRDOS,ERRlock));
2299
2300   seek_file(fnum,smb_offs);
2301   
2302   /* X/Open SMB protocol says that, unlike SMBwrite
2303      if the length is zero then NO truncation is
2304      done, just a write of zero. To truncate a file,
2305      use SMBwrite. */
2306   if(smb_dsize == 0)
2307     nwritten = 0;
2308   else
2309     nwritten = write_file(fnum,data,smb_dsize);
2310   
2311   if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0))
2312     return(UNIXERROR(ERRDOS,ERRnoaccess));
2313
2314   set_message(outbuf,6,0,True);
2315   
2316   SSVAL(outbuf,smb_vwv2,nwritten);
2317   
2318   if (nwritten < smb_dsize) {
2319     CVAL(outbuf,smb_rcls) = ERRHRD;
2320     SSVAL(outbuf,smb_err,ERRdiskfull);      
2321   }
2322
2323   DEBUG(3,("%s writeX fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,smb_dsize,nwritten));
2324
2325   chain_fnum = fnum;
2326
2327   if (lp_syncalways(SNUM(cnum)) || write_through)
2328     sync_file(fnum);
2329
2330   return chain_reply(inbuf,outbuf,length,bufsize);
2331 }
2332
2333
2334 /****************************************************************************
2335   reply to a lseek
2336 ****************************************************************************/
2337 int reply_lseek(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2338 {
2339   int cnum,fnum;
2340   uint32 startpos;
2341   int32 res= -1;
2342   int mode,umode;
2343   int outsize = 0;
2344   
2345   cnum = SVAL(inbuf,smb_tid);
2346   fnum = GETFNUM(inbuf,smb_vwv0);
2347
2348   CHECK_FNUM(fnum,cnum);
2349   CHECK_ERROR(fnum);
2350
2351   mode = SVAL(inbuf,smb_vwv1) & 3;
2352   startpos = IVAL(inbuf,smb_vwv2);
2353
2354   switch (mode & 3) 
2355     {
2356     case 0: umode = SEEK_SET; break;
2357     case 1: umode = SEEK_CUR; break;
2358     case 2: umode = SEEK_END; break;
2359     default:
2360       umode = SEEK_SET; break;
2361     }
2362   
2363   res = lseek(Files[fnum].fd_ptr->fd,startpos,umode);
2364   Files[fnum].pos = res;
2365   
2366   outsize = set_message(outbuf,2,0,True);
2367   SIVALS(outbuf,smb_vwv0,res);
2368   
2369   DEBUG(3,("%s lseek fnum=%d cnum=%d ofs=%d mode=%d\n",timestring(),fnum,cnum,startpos,mode));
2370   
2371   return(outsize);
2372 }
2373
2374
2375 /****************************************************************************
2376   reply to a flush
2377 ****************************************************************************/
2378 int reply_flush(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2379 {
2380   int cnum, fnum;
2381   int outsize = set_message(outbuf,0,0,True);
2382
2383   cnum = SVAL(inbuf,smb_tid);
2384   fnum = GETFNUM(inbuf,smb_vwv0);
2385
2386   if (fnum != 0xFFFF) {
2387     CHECK_FNUM(fnum,cnum);
2388     CHECK_ERROR(fnum);
2389   }
2390
2391   if (fnum == 0xFFFF)
2392     {
2393       int i;
2394       for (i=0;i<MAX_OPEN_FILES;i++)
2395         if (OPEN_FNUM(i))
2396           sync_file(i);
2397     }
2398   else
2399     sync_file(fnum);
2400
2401   DEBUG(3,("%s flush fnum=%d\n",timestring(),fnum));
2402   return(outsize);
2403 }
2404
2405
2406 /****************************************************************************
2407   reply to a exit
2408 ****************************************************************************/
2409 int reply_exit(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2410 {
2411   int outsize = set_message(outbuf,0,0,True);
2412   DEBUG(3,("%s exit\n",timestring()));
2413   
2414   return(outsize);
2415 }
2416
2417
2418 /****************************************************************************
2419   reply to a close
2420 ****************************************************************************/
2421 int reply_close(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2422 {
2423   int fnum,cnum;
2424   int outsize = 0;
2425   time_t mtime;
2426   int32 eclass = 0, err = 0;
2427
2428   outsize = set_message(outbuf,0,0,True);
2429
2430   cnum = SVAL(inbuf,smb_tid);
2431
2432   /* If it's an IPC, pass off to the pipe handler. */
2433   if (IS_IPC(cnum))
2434     return reply_pipe_close(inbuf,outbuf);
2435
2436   fnum = GETFNUM(inbuf,smb_vwv0);
2437
2438   CHECK_FNUM(fnum,cnum);
2439
2440   if(HAS_CACHED_ERROR(fnum)) {
2441     eclass = Files[fnum].wbmpx_ptr->wr_errclass;
2442     err = Files[fnum].wbmpx_ptr->wr_error;
2443   }
2444
2445   mtime = make_unix_date3(inbuf+smb_vwv1);
2446
2447   /* try and set the date */
2448   set_filetime(cnum, Files[fnum].name,mtime);
2449
2450   DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
2451            timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,
2452            Connections[cnum].num_files_open));
2453   
2454   close_file(fnum,True);
2455
2456   /* We have a cached error */
2457   if(eclass || err)
2458     return(ERROR(eclass,err));
2459
2460   return(outsize);
2461 }
2462
2463
2464 /****************************************************************************
2465   reply to a writeclose (Core+ protocol)
2466 ****************************************************************************/
2467 int reply_writeclose(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2468 {
2469   int cnum,numtowrite,fnum;
2470   int nwritten = -1;
2471   int outsize = 0;
2472   int startpos;
2473   char *data;
2474   time_t mtime;
2475   
2476   cnum = SVAL(inbuf,smb_tid);
2477   fnum = GETFNUM(inbuf,smb_vwv0);
2478
2479   CHECK_FNUM(fnum,cnum);
2480   CHECK_WRITE(fnum);
2481   CHECK_ERROR(fnum);
2482
2483   numtowrite = SVAL(inbuf,smb_vwv1);
2484   startpos = IVAL(inbuf,smb_vwv2);
2485   mtime = make_unix_date3(inbuf+smb_vwv4);
2486   data = smb_buf(inbuf) + 1;
2487   
2488   if (is_locked(fnum,cnum,numtowrite,startpos))
2489     return(ERROR(ERRDOS,ERRlock));
2490       
2491   seek_file(fnum,startpos);
2492       
2493   nwritten = write_file(fnum,data,numtowrite);
2494
2495   set_filetime(cnum, Files[fnum].name,mtime);
2496   
2497   close_file(fnum,True);
2498
2499   DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
2500            timestring(),fnum,cnum,numtowrite,nwritten,
2501            Connections[cnum].num_files_open));
2502   
2503   if (nwritten <= 0)
2504     return(UNIXERROR(ERRDOS,ERRnoaccess));
2505   
2506   outsize = set_message(outbuf,1,0,True);
2507   
2508   SSVAL(outbuf,smb_vwv0,nwritten);
2509   return(outsize);
2510 }
2511
2512
2513 /****************************************************************************
2514   reply to a lock
2515 ****************************************************************************/
2516 int reply_lock(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2517 {
2518   int fnum,cnum;
2519   int outsize = set_message(outbuf,0,0,True);
2520   uint32 count,offset;
2521   int eclass;
2522   uint32 ecode;
2523
2524   cnum = SVAL(inbuf,smb_tid);
2525   fnum = GETFNUM(inbuf,smb_vwv0);
2526
2527   CHECK_FNUM(fnum,cnum);
2528   CHECK_ERROR(fnum);
2529
2530   count = IVAL(inbuf,smb_vwv1);
2531   offset = IVAL(inbuf,smb_vwv3);
2532
2533   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));
2534
2535   if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
2536     return (ERROR(eclass,ecode));
2537   
2538   return(outsize);
2539 }
2540
2541
2542 /****************************************************************************
2543   reply to a unlock
2544 ****************************************************************************/
2545 int reply_unlock(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2546 {
2547   int fnum,cnum;
2548   int outsize = set_message(outbuf,0,0,True);
2549   uint32 count,offset;
2550   int eclass;
2551   uint32 ecode;
2552   
2553   cnum = SVAL(inbuf,smb_tid);
2554   fnum = GETFNUM(inbuf,smb_vwv0);
2555
2556   CHECK_FNUM(fnum,cnum);
2557   CHECK_ERROR(fnum);
2558
2559   count = IVAL(inbuf,smb_vwv1);
2560   offset = IVAL(inbuf,smb_vwv3);
2561
2562   if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode))
2563     return (ERROR(eclass,ecode));
2564
2565   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));
2566   
2567   return(outsize);
2568 }
2569
2570
2571 /****************************************************************************
2572   reply to a tdis
2573 ****************************************************************************/
2574 int reply_tdis(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2575 {
2576   int cnum;
2577   int outsize = set_message(outbuf,0,0,True);
2578   uint16 vuid;
2579
2580   cnum = SVAL(inbuf,smb_tid);
2581   vuid = SVAL(inbuf,smb_uid);
2582
2583   if (!OPEN_CNUM(cnum)) {
2584     DEBUG(4,("Invalid cnum in tdis (%d)\n",cnum));
2585     return(ERROR(ERRSRV,ERRinvnid));
2586   }
2587
2588   Connections[cnum].used = False;
2589
2590   close_cnum(cnum,vuid);
2591   
2592   DEBUG(3,("%s tdis cnum=%d\n",timestring(),cnum));
2593
2594   return outsize;
2595 }
2596
2597
2598
2599 /****************************************************************************
2600   reply to a echo
2601 ****************************************************************************/
2602 int reply_echo(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2603 {
2604   int cnum;
2605   int smb_reverb = SVAL(inbuf,smb_vwv0);
2606   int seq_num;
2607   int data_len = smb_buflen(inbuf);
2608   int outsize = set_message(outbuf,1,data_len,True);
2609
2610   cnum = SVAL(inbuf,smb_tid);
2611
2612   /* According to the latest CIFS spec we shouldn't
2613      care what the TID is.
2614    */
2615
2616 #if 0
2617   if (cnum != 0xFFFF && !OPEN_CNUM(cnum))
2618     {
2619       DEBUG(4,("Invalid cnum in echo (%d)\n",cnum));
2620       return(ERROR(ERRSRV,ERRinvnid));
2621     }
2622 #endif
2623
2624   /* copy any incoming data back out */
2625   if (data_len > 0)
2626     memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
2627
2628   if (smb_reverb > 100)
2629     {
2630       DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
2631       smb_reverb = 100;
2632     }
2633
2634   for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++)
2635     {
2636       SSVAL(outbuf,smb_vwv0,seq_num);
2637
2638       smb_setlen(outbuf,outsize - 4);
2639
2640       send_smb(Client,outbuf);
2641     }
2642
2643   DEBUG(3,("%s echo %d times cnum=%d\n",timestring(),smb_reverb,cnum));
2644
2645   return -1;
2646 }
2647
2648
2649 /****************************************************************************
2650   reply to a printopen
2651 ****************************************************************************/
2652 int reply_printopen(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2653 {
2654   pstring fname;
2655   pstring fname2;
2656   int cnum;
2657   int fnum = -1;
2658   int outsize = 0;
2659
2660   *fname = *fname2 = 0;
2661
2662   cnum = SVAL(inbuf,smb_tid);
2663
2664   if (!CAN_PRINT(cnum))
2665     return(ERROR(ERRDOS,ERRnoaccess));
2666
2667   {
2668     pstring s;
2669     char *p;
2670     pstrcpy(s,smb_buf(inbuf)+1);
2671     p = s;
2672     while (*p)
2673       {
2674         if (!(isalnum(*p) || strchr("._-",*p)))
2675           *p = 'X';
2676         p++;
2677       }
2678
2679     if (strlen(s) > 10) s[10] = 0;
2680
2681     slprintf(fname,sizeof(fname)-1, "%s.XXXXXX",s);  
2682   }
2683
2684   fnum = find_free_file();
2685   if (fnum < 0)
2686     return(ERROR(ERRSRV,ERRnofids));
2687
2688   pstrcpy(fname2,(char *)mktemp(fname));
2689
2690   if (!check_name(fname2,cnum)) {
2691           Files[fnum].reserved = False;
2692           return(ERROR(ERRDOS,ERRnoaccess));
2693   }
2694
2695   /* Open for exclusive use, write only. */
2696   open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0), 
2697                    0, NULL, NULL);
2698
2699   if (!Files[fnum].open) {
2700           Files[fnum].reserved = False;
2701           return(UNIXERROR(ERRDOS,ERRnoaccess));
2702   }
2703
2704   /* force it to be a print file */
2705   Files[fnum].print_file = True;
2706   
2707   outsize = set_message(outbuf,1,0,True);
2708   SSVAL(outbuf,smb_vwv0,fnum);
2709   
2710   DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum));
2711   
2712   return(outsize);
2713 }
2714
2715
2716 /****************************************************************************
2717   reply to a printclose
2718 ****************************************************************************/
2719 int reply_printclose(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2720 {
2721   int fnum,cnum;
2722   int outsize = set_message(outbuf,0,0,True);
2723   
2724   cnum = SVAL(inbuf,smb_tid);
2725   fnum = GETFNUM(inbuf,smb_vwv0);
2726
2727   CHECK_FNUM(fnum,cnum);
2728   CHECK_ERROR(fnum);
2729
2730   if (!CAN_PRINT(cnum))
2731     return(ERROR(ERRDOS,ERRnoaccess));
2732   
2733   DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum));
2734   
2735   close_file(fnum,True);
2736
2737   return(outsize);
2738 }
2739
2740
2741 /****************************************************************************
2742   reply to a printqueue
2743 ****************************************************************************/
2744 int reply_printqueue(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2745 {
2746   int cnum;
2747   int outsize = set_message(outbuf,2,3,True);
2748   int max_count = SVAL(inbuf,smb_vwv0);
2749   int start_index = SVAL(inbuf,smb_vwv1);
2750   uint16 vuid;
2751
2752   cnum = SVAL(inbuf,smb_tid);
2753   vuid = SVAL(inbuf,smb_uid);
2754
2755 /* allow checking the queue for anyone */
2756 #if 0
2757   if (!CAN_PRINT(cnum))
2758     return(ERROR(ERRDOS,ERRnoaccess));
2759 #endif
2760
2761   SSVAL(outbuf,smb_vwv0,0);
2762   SSVAL(outbuf,smb_vwv1,0);
2763   CVAL(smb_buf(outbuf),0) = 1;
2764   SSVAL(smb_buf(outbuf),1,0);
2765   
2766   DEBUG(3,("%s printqueue cnum=%d start_index=%d max_count=%d\n",
2767         timestring(),cnum,start_index,max_count));
2768
2769   if (!OPEN_CNUM(cnum) || !Connections[cnum].printer)
2770     {
2771       int i;
2772       cnum = -1;
2773
2774       for (i=0;i<MAX_CONNECTIONS;i++)
2775         if (CAN_PRINT(i) && Connections[i].printer)
2776           cnum = i;
2777
2778       if (cnum == -1)
2779         for (i=0;i<MAX_CONNECTIONS;i++)
2780           if (OPEN_CNUM(i))
2781             cnum = i;
2782
2783       if (!OPEN_CNUM(cnum))
2784         return(ERROR(ERRSRV,ERRinvnid));
2785
2786       DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
2787     }
2788
2789   if (!become_user(&Connections[cnum], cnum, vuid))
2790     return(ERROR(ERRSRV,ERRinvnid));
2791
2792   {
2793     print_queue_struct *queue = NULL;
2794     char *p = smb_buf(outbuf) + 3;
2795     int count = get_printqueue(SNUM(cnum),cnum,&queue,NULL);
2796     int num_to_get = ABS(max_count);
2797     int first = (max_count>0?start_index:start_index+max_count+1);
2798     int i;
2799
2800     if (first >= count)
2801       num_to_get = 0;
2802     else
2803       num_to_get = MIN(num_to_get,count-first);
2804     
2805
2806     for (i=first;i<first+num_to_get;i++)
2807       {
2808         put_dos_date2(p,0,queue[i].time);
2809         CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
2810         SSVAL(p,5,printjob_encode(SNUM(cnum), queue[i].job));
2811         SIVAL(p,7,queue[i].size);
2812         CVAL(p,11) = 0;
2813         StrnCpy(p+12,queue[i].user,16);
2814         p += 28;
2815       }
2816
2817     if (count > 0)
2818       {
2819         outsize = set_message(outbuf,2,28*count+3,False);         
2820         SSVAL(outbuf,smb_vwv0,count);
2821         SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
2822         CVAL(smb_buf(outbuf),0) = 1;
2823         SSVAL(smb_buf(outbuf),1,28*count);
2824       }
2825
2826     if (queue) free(queue);
2827           
2828     DEBUG(3,("%d entries returned in queue\n",count));
2829   }
2830   
2831   return(outsize);
2832 }
2833
2834
2835 /****************************************************************************
2836   reply to a printwrite
2837 ****************************************************************************/
2838 int reply_printwrite(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2839 {
2840   int cnum,numtowrite,fnum;
2841   int outsize = set_message(outbuf,0,0,True);
2842   char *data;
2843   
2844   cnum = SVAL(inbuf,smb_tid);
2845
2846   if (!CAN_PRINT(cnum))
2847     return(ERROR(ERRDOS,ERRnoaccess));
2848
2849   fnum = GETFNUM(inbuf,smb_vwv0);
2850
2851   CHECK_FNUM(fnum,cnum);
2852   CHECK_WRITE(fnum);
2853   CHECK_ERROR(fnum);
2854
2855   numtowrite = SVAL(smb_buf(inbuf),1);
2856   data = smb_buf(inbuf) + 3;
2857   
2858   if (write_file(fnum,data,numtowrite) != numtowrite)
2859     return(UNIXERROR(ERRDOS,ERRnoaccess));
2860   
2861   DEBUG(3,("%s printwrite fnum=%d cnum=%d num=%d\n",timestring(),fnum,cnum,numtowrite));
2862   
2863   return(outsize);
2864 }
2865
2866
2867 /****************************************************************************
2868   reply to a mkdir
2869 ****************************************************************************/
2870 int reply_mkdir(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2871 {
2872   pstring directory;
2873   int cnum;
2874   int outsize,ret= -1;
2875   BOOL bad_path = False;
2876  
2877   pstrcpy(directory,smb_buf(inbuf) + 1);
2878   cnum = SVAL(inbuf,smb_tid);
2879   unix_convert(directory,cnum,0,&bad_path);
2880   
2881   if (check_name(directory,cnum))
2882     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
2883   
2884   if (ret < 0)
2885   {
2886     if((errno == ENOENT) && bad_path)
2887     {
2888       unix_ERR_class = ERRDOS;
2889       unix_ERR_code = ERRbadpath;
2890     }
2891     return(UNIXERROR(ERRDOS,ERRnoaccess));
2892   }
2893  
2894   outsize = set_message(outbuf,0,0,True);
2895   
2896   DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
2897   
2898   return(outsize);
2899 }
2900
2901 /****************************************************************************
2902 Static function used by reply_rmdir to delete an entire directory
2903 tree recursively.
2904 ****************************************************************************/
2905 static BOOL recursive_rmdir(char *directory)
2906 {
2907   char *dname = NULL;
2908   BOOL ret = False;
2909   void *dirptr = OpenDir(-1, directory, False);
2910
2911   if(dirptr == NULL)
2912     return True;
2913
2914   while((dname = ReadDirName(dirptr)))
2915   {
2916     pstring fullname;
2917     struct stat st;
2918
2919     if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2920       continue;
2921
2922     /* Construct the full name. */
2923     if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
2924     {
2925       errno = ENOMEM;
2926       ret = True;
2927       break;
2928     }
2929     pstrcpy(fullname, directory);
2930     pstrcat(fullname, "/");
2931     pstrcat(fullname, dname);
2932
2933     if(sys_lstat(fullname, &st) != 0)
2934     {
2935       ret = True;
2936       break;
2937     }
2938
2939     if(st.st_mode & S_IFDIR)
2940     {
2941       if(recursive_rmdir(fullname)!=0)
2942       {
2943         ret = True;
2944         break;
2945       }
2946       if(sys_rmdir(fullname) != 0)
2947       {
2948         ret = True;
2949         break;
2950       }
2951     }
2952     else if(sys_unlink(fullname) != 0)
2953     {
2954       ret = True;
2955       break;
2956     }
2957   }
2958   CloseDir(dirptr);
2959   return ret;
2960 }
2961
2962 /****************************************************************************
2963   reply to a rmdir
2964 ****************************************************************************/
2965 int reply_rmdir(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2966 {
2967   pstring directory;
2968   int cnum;
2969   int outsize = 0;
2970   BOOL ok = False;
2971   BOOL bad_path = False;
2972
2973   cnum = SVAL(inbuf,smb_tid);
2974   pstrcpy(directory,smb_buf(inbuf) + 1);
2975   unix_convert(directory,cnum,0,&bad_path);
2976   
2977   if (check_name(directory,cnum))
2978     {
2979
2980       dptr_closepath(directory,SVAL(inbuf,smb_pid));
2981       ok = (sys_rmdir(directory) == 0);
2982       if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(cnum)))
2983         {
2984           /* Check to see if the only thing in this directory are
2985              vetoed files/directories. If so then delete them and
2986              retry. If we fail to delete any of them (and we *don't*
2987              do a recursive delete) then fail the rmdir. */
2988           BOOL all_veto_files = True;
2989           char *dname;
2990           void *dirptr = OpenDir(cnum, directory, False);
2991
2992           if(dirptr != NULL)
2993             {
2994               int dirpos = TellDir(dirptr);
2995                   while ((dname = ReadDirName(dirptr)))
2996                     {
2997                   if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2998                     continue;
2999                   if(!IS_VETO_PATH(cnum, dname))
3000                     {
3001                       all_veto_files = False;
3002                       break;
3003                     }
3004                 }
3005               if(all_veto_files)
3006                 {
3007                   SeekDir(dirptr,dirpos);
3008                   while ((dname = ReadDirName(dirptr)))
3009                     {
3010                       pstring fullname;
3011                       struct stat st;
3012
3013                       if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3014                         continue;
3015
3016                       /* Construct the full name. */
3017                       if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
3018                         {
3019                           errno = ENOMEM;
3020                           break;
3021                         }
3022                       pstrcpy(fullname, directory);
3023                       pstrcat(fullname, "/");
3024                       pstrcat(fullname, dname);
3025                       
3026                       if(sys_lstat(fullname, &st) != 0)
3027                         break;
3028                       if(st.st_mode & S_IFDIR)
3029                       {
3030                         if(lp_recursive_veto_delete(SNUM(cnum)))
3031                         {
3032                           if(recursive_rmdir(fullname) != 0)
3033                             break;
3034                         }
3035                         if(sys_rmdir(fullname) != 0)
3036                           break;
3037                       }
3038                       else if(sys_unlink(fullname) != 0)
3039                         break;
3040                     }
3041                   CloseDir(dirptr);
3042                   /* Retry the rmdir */
3043                   ok = (sys_rmdir(directory) == 0);
3044                 }
3045               else
3046                 CloseDir(dirptr);
3047             }
3048           else
3049             errno = ENOTEMPTY;
3050          }
3051           
3052       if (!ok)
3053         DEBUG(3,("couldn't remove directory %s : %s\n",
3054                  directory,strerror(errno)));
3055     }
3056   
3057   if (!ok)
3058   {
3059     if((errno == ENOENT) && bad_path)
3060     {
3061       unix_ERR_class = ERRDOS;
3062       unix_ERR_code = ERRbadpath;
3063     }
3064     return(UNIXERROR(ERRDOS,ERRbadpath));
3065   }
3066  
3067   outsize = set_message(outbuf,0,0,True);
3068   
3069   DEBUG(3,("%s rmdir %s\n",timestring(),directory));
3070   
3071   return(outsize);
3072 }
3073
3074
3075 /*******************************************************************
3076 resolve wildcards in a filename rename
3077 ********************************************************************/
3078 static BOOL resolve_wildcards(char *name1,char *name2)
3079 {
3080   fstring root1,root2;
3081   fstring ext1,ext2;
3082   char *p,*p2;
3083
3084   name1 = strrchr(name1,'/');
3085   name2 = strrchr(name2,'/');
3086
3087   if (!name1 || !name2) return(False);
3088   
3089   fstrcpy(root1,name1);
3090   fstrcpy(root2,name2);
3091   p = strrchr(root1,'.');
3092   if (p) {
3093     *p = 0;
3094     fstrcpy(ext1,p+1);
3095   } else {
3096     fstrcpy(ext1,"");    
3097   }
3098   p = strrchr(root2,'.');
3099   if (p) {
3100     *p = 0;
3101     fstrcpy(ext2,p+1);
3102   } else {
3103     fstrcpy(ext2,"");    
3104   }
3105
3106   p = root1;
3107   p2 = root2;
3108   while (*p2) {
3109     if (*p2 == '?') {
3110       *p2 = *p;
3111       p2++;
3112     } else {
3113       p2++;
3114     }
3115     if (*p) p++;
3116   }
3117
3118   p = ext1;
3119   p2 = ext2;
3120   while (*p2) {
3121     if (*p2 == '?') {
3122       *p2 = *p;
3123       p2++;
3124     } else {
3125       p2++;
3126     }
3127     if (*p) p++;
3128   }
3129
3130   pstrcpy(name2,root2);
3131   if (ext2[0]) {
3132     pstrcat(name2,".");
3133     pstrcat(name2,ext2);
3134   }
3135
3136   return(True);
3137 }
3138
3139 /*******************************************************************
3140 check if a user is allowed to rename a file
3141 ********************************************************************/
3142 static BOOL can_rename(char *fname,int cnum)
3143 {
3144   struct stat sbuf;
3145
3146   if (!CAN_WRITE(cnum)) return(False);
3147
3148   if (sys_lstat(fname,&sbuf) != 0) return(False);
3149   if (!check_file_sharing(cnum,fname,True)) return(False);
3150
3151   return(True);
3152 }
3153
3154 /****************************************************************************
3155   reply to a mv
3156 ****************************************************************************/
3157 int reply_mv(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3158 {
3159   int outsize = 0;
3160   pstring name;
3161   int cnum;
3162   pstring directory;
3163   pstring mask,newname;
3164   pstring newname_last_component;
3165   char *p;
3166   int count=0;
3167   int error = ERRnoaccess;
3168   BOOL has_wild;
3169   BOOL exists=False;
3170   BOOL bad_path1 = False;
3171   BOOL bad_path2 = False;
3172
3173   *directory = *mask = 0;
3174
3175   cnum = SVAL(inbuf,smb_tid);
3176   
3177   pstrcpy(name,smb_buf(inbuf) + 1);
3178   pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
3179    
3180   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
3181    
3182   unix_convert(name,cnum,0,&bad_path1);
3183   unix_convert(newname,cnum,newname_last_component,&bad_path2);
3184
3185   /*
3186    * Split the old name into directory and last component
3187    * strings. Note that unix_convert may have stripped off a 
3188    * leading ./ from both name and newname if the rename is 
3189    * at the root of the share. We need to make sure either both
3190    * name and newname contain a / character or neither of them do
3191    * as this is checked in resolve_wildcards().
3192    */
3193
3194   p = strrchr(name,'/');
3195   if (!p) {
3196     pstrcpy(directory,".");
3197     pstrcpy(mask,name);
3198   } else {
3199     *p = 0;
3200     pstrcpy(directory,name);
3201     pstrcpy(mask,p+1);
3202     *p = '/'; /* Replace needed for exceptional test below. */
3203   }
3204
3205   if (is_mangled(mask))
3206     check_mangled_cache( mask );
3207
3208   has_wild = strchr(mask,'*') || strchr(mask,'?');
3209
3210   if (!has_wild) {
3211     BOOL is_short_name = is_8_3(name, True);
3212
3213     /* Add a terminating '/' to the directory name. */
3214     pstrcat(directory,"/");
3215     pstrcat(directory,mask);
3216
3217     /* Ensure newname contains a '/' also */
3218     if(strrchr(newname,'/') == 0) {
3219       pstring tmpstr;
3220
3221       pstrcpy(tmpstr, "./");
3222       pstrcat(tmpstr, newname);
3223       pstrcpy(newname, tmpstr);
3224     }
3225   
3226     DEBUG(3,("reply_mv : case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 
3227             case_sensitive, case_preserve, short_case_preserve, directory, 
3228             newname, newname_last_component, is_short_name));
3229
3230     /*
3231      * Check for special case with case preserving and not
3232      * case sensitive, if directory and newname are identical,
3233      * and the old last component differs from the original
3234      * last component only by case, then we should allow
3235      * the rename (user is trying to change the case of the
3236      * filename).
3237      */
3238     if((case_sensitive == False) && ( ((case_preserve == True) && (is_short_name == False)) || 
3239             ((short_case_preserve == True) && (is_short_name == True))) &&
3240        strcsequal(directory, newname)) {
3241       pstring newname_modified_last_component;
3242
3243       /*
3244        * Get the last component of the modified name.
3245        * Note that we guarantee that newname contains a '/'
3246        * character above.
3247        */
3248       p = strrchr(newname,'/');
3249       pstrcpy(newname_modified_last_component,p+1);
3250
3251       if(strcsequal(newname_modified_last_component, 
3252                     newname_last_component) == False) {
3253         /*
3254          * Replace the modified last component with
3255          * the original.
3256          */
3257         pstrcpy(p+1, newname_last_component);
3258       }
3259     }
3260
3261     if (resolve_wildcards(directory,newname) && 
3262         can_rename(directory,cnum) && 
3263         !file_exist(newname,NULL) &&
3264         !sys_rename(directory,newname)) count++;
3265
3266     DEBUG(3,("reply_mv : %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
3267                          directory,newname));
3268
3269     if (!count) exists = file_exist(directory,NULL);
3270     if (!count && exists && file_exist(newname,NULL)) {
3271       exists = True;
3272       error = 183;
3273     }
3274   } else {
3275     void *dirptr = NULL;
3276     char *dname;
3277     pstring destname;
3278
3279     if (check_name(directory,cnum))
3280       dirptr = OpenDir(cnum, directory, True);
3281
3282     if (dirptr)
3283       {
3284         error = ERRbadfile;
3285
3286         if (strequal(mask,"????????.???"))
3287           pstrcpy(mask,"*");
3288
3289         while ((dname = ReadDirName(dirptr)))
3290           {
3291             pstring fname;
3292             pstrcpy(fname,dname);
3293             
3294             if(!mask_match(fname, mask, case_sensitive, False)) continue;
3295
3296             error = ERRnoaccess;
3297             slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
3298             if (!can_rename(fname,cnum)) {
3299                     DEBUG(6,("rename %s refused\n", fname));
3300                     continue;
3301             }
3302             pstrcpy(destname,newname);
3303
3304             if (!resolve_wildcards(fname,destname)) {
3305                     DEBUG(6,("resolve_wildcards %s %s failed\n", 
3306                              fname, destname));
3307                     continue;
3308             }
3309
3310             if (file_exist(destname,NULL)) {
3311                     DEBUG(6,("file_exist %s\n", 
3312                              destname));
3313                     error = 183;
3314                     continue;
3315             }
3316             if (!sys_rename(fname,destname)) count++;
3317             DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
3318           }
3319         CloseDir(dirptr);
3320       }
3321   }
3322   
3323   if (count == 0) {
3324     if (exists)
3325       return(ERROR(ERRDOS,error));
3326     else
3327     {
3328       if((errno == ENOENT) && (bad_path1 || bad_path2))
3329       {
3330         unix_ERR_class = ERRDOS;
3331         unix_ERR_code = ERRbadpath;
3332       }
3333       return(UNIXERROR(ERRDOS,error));
3334     }
3335   }
3336   
3337   outsize = set_message(outbuf,0,0,True);
3338   
3339   return(outsize);
3340 }
3341
3342 /*******************************************************************
3343   copy a file as part of a reply_copy
3344   ******************************************************************/
3345 static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
3346                       int count,BOOL target_is_directory)
3347 {
3348   int Access,action;
3349   struct stat st;
3350   int ret=0;
3351   int fnum1,fnum2;
3352   pstring dest;
3353   
3354   pstrcpy(dest,dest1);
3355   if (target_is_directory) {
3356     char *p = strrchr(src,'/');
3357     if (p) 
3358       p++;
3359     else
3360       p = src;
3361     pstrcat(dest,"/");
3362     pstrcat(dest,p);
3363   }
3364
3365   if (!file_exist(src,&st)) return(False);
3366
3367   fnum1 = find_free_file();
3368   if (fnum1<0) return(False);
3369   open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
3370                    1,0,0,&Access,&action);
3371
3372   if (!Files[fnum1].open) {
3373           Files[fnum1].reserved = False;
3374           return(False);
3375   }
3376
3377   if (!target_is_directory && count)
3378     ofun = 1;
3379
3380   fnum2 = find_free_file();
3381   if (fnum2<0) {
3382     close_file(fnum1,False);
3383     return(False);
3384   }
3385   open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
3386                    ofun,st.st_mode,0,&Access,&action);
3387
3388   if (!Files[fnum2].open) {
3389     close_file(fnum1,False);
3390     Files[fnum2].reserved = False;
3391     return(False);
3392   }
3393
3394   if ((ofun&3) == 1) {
3395     lseek(Files[fnum2].fd_ptr->fd,0,SEEK_END);
3396   }
3397   
3398   if (st.st_size)
3399     ret = transfer_file(Files[fnum1].fd_ptr->fd,Files[fnum2].fd_ptr->fd,st.st_size,NULL,0,0);
3400
3401   close_file(fnum1,False);
3402   close_file(fnum2,False);
3403
3404   return(ret == st.st_size);
3405 }
3406
3407
3408
3409 /****************************************************************************
3410   reply to a file copy.
3411   ****************************************************************************/
3412 int reply_copy(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3413 {
3414   int outsize = 0;
3415   pstring name;
3416   int cnum;
3417   pstring directory;
3418   pstring mask,newname;
3419   char *p;
3420   int count=0;
3421   int error = ERRnoaccess;
3422   BOOL has_wild;
3423   BOOL exists=False;
3424   int tid2 = SVAL(inbuf,smb_vwv0);
3425   int ofun = SVAL(inbuf,smb_vwv1);
3426   int flags = SVAL(inbuf,smb_vwv2);
3427   BOOL target_is_directory=False;
3428   BOOL bad_path1 = False;
3429   BOOL bad_path2 = False;
3430
3431   *directory = *mask = 0;
3432
3433   cnum = SVAL(inbuf,smb_tid);
3434   
3435   pstrcpy(name,smb_buf(inbuf));
3436   pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
3437    
3438   DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
3439    
3440   if (tid2 != cnum) {
3441     /* can't currently handle inter share copies XXXX */
3442     DEBUG(3,("Rejecting inter-share copy\n"));
3443     return(ERROR(ERRSRV,ERRinvdevice));
3444   }
3445
3446   unix_convert(name,cnum,0,&bad_path1);
3447   unix_convert(newname,cnum,0,&bad_path2);
3448
3449   target_is_directory = directory_exist(newname,NULL);
3450
3451   if ((flags&1) && target_is_directory) {
3452     return(ERROR(ERRDOS,ERRbadfile));
3453   }
3454
3455   if ((flags&2) && !target_is_directory) {
3456     return(ERROR(ERRDOS,ERRbadpath));
3457   }
3458
3459   if ((flags&(1<<5)) && directory_exist(name,NULL)) {
3460     /* wants a tree copy! XXXX */
3461     DEBUG(3,("Rejecting tree copy\n"));
3462     return(ERROR(ERRSRV,ERRerror));    
3463   }
3464
3465   p = strrchr(name,'/');
3466   if (!p) {
3467     pstrcpy(directory,"./");
3468     pstrcpy(mask,name);
3469   } else {
3470     *p = 0;
3471     pstrcpy(directory,name);
3472     pstrcpy(mask,p+1);
3473   }
3474
3475   if (is_mangled(mask))
3476     check_mangled_cache( mask );
3477
3478   has_wild = strchr(mask,'*') || strchr(mask,'?');
3479
3480   if (!has_wild) {
3481     pstrcat(directory,"/");
3482     pstrcat(directory,mask);
3483     if (resolve_wildcards(directory,newname) && 
3484         copy_file(directory,newname,cnum,ofun,
3485                   count,target_is_directory)) count++;
3486     if (!count) exists = file_exist(directory,NULL);
3487   } else {
3488     void *dirptr = NULL;
3489     char *dname;
3490     pstring destname;
3491
3492     if (check_name(directory,cnum))
3493       dirptr = OpenDir(cnum, directory, True);
3494
3495     if (dirptr)
3496       {
3497         error = ERRbadfile;
3498
3499         if (strequal(mask,"????????.???"))
3500           pstrcpy(mask,"*");
3501
3502         while ((dname = ReadDirName(dirptr)))
3503           {
3504             pstring fname;
3505             pstrcpy(fname,dname);
3506             
3507             if(!mask_match(fname, mask, case_sensitive, False)) continue;
3508
3509             error = ERRnoaccess;
3510             slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
3511             pstrcpy(destname,newname);
3512             if (resolve_wildcards(fname,destname) && 
3513                 copy_file(directory,newname,cnum,ofun,
3514                           count,target_is_directory)) count++;
3515             DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
3516           }
3517         CloseDir(dirptr);
3518       }
3519   }
3520   
3521   if (count == 0) {
3522     if (exists)
3523       return(ERROR(ERRDOS,error));
3524     else
3525     {
3526       if((errno == ENOENT) && (bad_path1 || bad_path2))
3527       {
3528         unix_ERR_class = ERRDOS;
3529         unix_ERR_code = ERRbadpath;
3530       }
3531       return(UNIXERROR(ERRDOS,error));
3532     }
3533   }
3534   
3535   outsize = set_message(outbuf,1,0,True);
3536   SSVAL(outbuf,smb_vwv0,count);
3537
3538   return(outsize);
3539 }
3540
3541
3542
3543 /****************************************************************************
3544   reply to a setdir
3545 ****************************************************************************/
3546 int reply_setdir(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3547 {
3548   int cnum,snum;
3549   int outsize = 0;
3550   BOOL ok = False;
3551   pstring newdir;
3552   
3553   cnum = SVAL(inbuf,smb_tid);
3554   
3555   snum = Connections[cnum].service;
3556   if (!CAN_SETDIR(snum))
3557     return(ERROR(ERRDOS,ERRnoaccess));
3558   
3559   pstrcpy(newdir,smb_buf(inbuf) + 1);
3560   strlower(newdir);
3561   
3562   if (strlen(newdir) == 0)
3563     ok = True;
3564   else
3565     {
3566       ok = directory_exist(newdir,NULL);
3567       if (ok)
3568         string_set(&Connections[cnum].connectpath,newdir);
3569     }
3570   
3571   if (!ok)
3572     return(ERROR(ERRDOS,ERRbadpath));
3573   
3574   outsize = set_message(outbuf,0,0,True);
3575   CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
3576   
3577   DEBUG(3,("%s setdir %s cnum=%d\n",timestring(),newdir,cnum));
3578   
3579   return(outsize);
3580 }
3581
3582
3583 /****************************************************************************
3584   reply to a lockingX request
3585 ****************************************************************************/
3586 int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
3587 {
3588   int fnum = GETFNUM(inbuf,smb_vwv2);
3589   unsigned char locktype = CVAL(inbuf,smb_vwv3);
3590 #if 0
3591   unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
3592 #endif
3593   uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
3594   uint16 num_locks = SVAL(inbuf,smb_vwv7);
3595   uint32 count, offset;
3596
3597   int cnum;
3598   int i;
3599   char *data;
3600   uint32 ecode=0, dummy2;
3601   int eclass=0, dummy1;
3602
3603   cnum = SVAL(inbuf,smb_tid);
3604
3605   CHECK_FNUM(fnum,cnum);
3606   CHECK_ERROR(fnum);
3607
3608   data = smb_buf(inbuf);
3609
3610   /* Check if this is an oplock break on a file
3611      we have granted an oplock on.
3612    */
3613   if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
3614   {
3615     int token;
3616     files_struct *fsp = &Files[fnum];
3617     uint32 dev = fsp->fd_ptr->dev;
3618     uint32 inode = fsp->fd_ptr->inode;
3619
3620     DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
3621               fnum));
3622     /*
3623      * Make sure we have granted an oplock on this file.
3624      */
3625     if(!fsp->granted_oplock)
3626     {
3627       DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
3628 no oplock granted on this file.\n", fnum));
3629       return ERROR(ERRDOS,ERRlock);
3630     }
3631
3632     /* Remove the oplock flag from the sharemode. */
3633     lock_share_entry(fsp->cnum, dev, inode, &token);
3634     if(remove_share_oplock( fnum, token)==False) {
3635             DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
3636 dev = %x, inode = %x\n", 
3637                      fnum, dev, inode));
3638             unlock_share_entry(fsp->cnum, dev, inode, token);
3639     } else {
3640             unlock_share_entry(fsp->cnum, dev, inode, token);
3641
3642             /* Clear the granted flag and return. */
3643             fsp->granted_oplock = False;
3644     }
3645
3646     /* if this is a pure oplock break request then don't send a reply */
3647     if (num_locks == 0 && num_ulocks == 0)
3648     {
3649       /* Sanity check - ensure a pure oplock break is not a
3650          chained request. */
3651       if(CVAL(inbuf,smb_vwv0) != 0xff)
3652         DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
3653                  (unsigned int)CVAL(inbuf,smb_vwv0) ));
3654       return -1;
3655     }
3656   }
3657
3658   /* Data now points at the beginning of the list
3659      of smb_unlkrng structs */
3660   for(i = 0; i < (int)num_ulocks; i++) {
3661     count = IVAL(data,SMB_LKLEN_OFFSET(i));
3662     offset = IVAL(data,SMB_LKOFF_OFFSET(i));
3663     if(!do_unlock(fnum,cnum,count,offset,&eclass, &ecode))
3664       return ERROR(eclass,ecode);
3665   }
3666
3667   /* Now do any requested locks */
3668   data += 10*num_ulocks;
3669   /* Data now points at the beginning of the list
3670      of smb_lkrng structs */
3671   for(i = 0; i < (int)num_locks; i++) {
3672     count = IVAL(data,SMB_LKLEN_OFFSET(i)); 
3673     offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
3674     if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode))
3675       break;
3676   }
3677
3678   /* If any of the above locks failed, then we must unlock
3679      all of the previous locks (X/Open spec). */
3680   if(i != num_locks && num_locks != 0) {
3681     for(; i >= 0; i--) {
3682       count = IVAL(data,SMB_LKLEN_OFFSET(i));  
3683       offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
3684       do_unlock(fnum,cnum,count,offset,&dummy1,&dummy2);
3685     }
3686     return ERROR(eclass,ecode);
3687   }
3688
3689   set_message(outbuf,2,0,True);
3690   
3691   DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
3692         timestring(),fnum,cnum,(unsigned int)locktype,num_locks,num_ulocks));
3693
3694   chain_fnum = fnum;
3695
3696   return chain_reply(inbuf,outbuf,length,bufsize);
3697 }
3698
3699
3700 /****************************************************************************
3701   reply to a SMBreadbmpx (read block multiplex) request
3702 ****************************************************************************/
3703 int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
3704 {
3705   int cnum,fnum;
3706   int nread = -1;
3707   int total_read;
3708   char *data;
3709   uint32 startpos;
3710   int outsize, mincount, maxcount;
3711   int max_per_packet;
3712   int tcount;
3713   int pad;
3714
3715   /* this function doesn't seem to work - disable by default */
3716   if (!lp_readbmpx())
3717     return(ERROR(ERRSRV,ERRuseSTD));
3718
3719   outsize = set_message(outbuf,8,0,True);
3720
3721   cnum = SVAL(inbuf,smb_tid);
3722   fnum = GETFNUM(inbuf,smb_vwv0);
3723
3724   CHECK_FNUM(fnum,cnum);
3725   CHECK_READ(fnum);
3726   CHECK_ERROR(fnum);
3727
3728   startpos = IVAL(inbuf,smb_vwv1);
3729   maxcount = SVAL(inbuf,smb_vwv3);
3730   mincount = SVAL(inbuf,smb_vwv4);
3731
3732   data = smb_buf(outbuf);
3733   pad = ((long)data)%4;
3734   if (pad) pad = 4 - pad;
3735   data += pad;
3736
3737   max_per_packet = bufsize-(outsize+pad);
3738   tcount = maxcount;
3739   total_read = 0;
3740
3741   if (is_locked(fnum,cnum,maxcount,startpos))
3742     return(ERROR(ERRDOS,ERRlock));
3743         
3744   do
3745     {
3746       int N = MIN(max_per_packet,tcount-total_read);
3747   
3748       nread = read_file(fnum,data,startpos,N);
3749
3750       if (nread <= 0) nread = 0;
3751
3752       if (nread < N)
3753         tcount = total_read + nread;
3754
3755       set_message(outbuf,8,nread,False);
3756       SIVAL(outbuf,smb_vwv0,startpos);
3757       SSVAL(outbuf,smb_vwv2,tcount);
3758       SSVAL(outbuf,smb_vwv6,nread);
3759       SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
3760
3761       send_smb(Client,outbuf);
3762
3763       total_read += nread;
3764       startpos += nread;
3765     }
3766   while (total_read < tcount);
3767
3768   return(-1);
3769 }
3770
3771
3772 /****************************************************************************
3773   reply to a SMBwritebmpx (write block multiplex primary) request
3774 ****************************************************************************/
3775 int reply_writebmpx(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3776 {
3777   int cnum,numtowrite,fnum;
3778   int nwritten = -1;
3779   int outsize = 0;
3780   uint32 startpos;
3781   int tcount, write_through, smb_doff;
3782   char *data;
3783   
3784   cnum = SVAL(inbuf,smb_tid);
3785   fnum = GETFNUM(inbuf,smb_vwv0);
3786
3787   CHECK_FNUM(fnum,cnum);
3788   CHECK_WRITE(fnum);
3789   CHECK_ERROR(fnum);
3790
3791   tcount = SVAL(inbuf,smb_vwv1);
3792   startpos = IVAL(inbuf,smb_vwv3);
3793   write_through = BITSETW(inbuf+smb_vwv7,0);
3794   numtowrite = SVAL(inbuf,smb_vwv10);
3795   smb_doff = SVAL(inbuf,smb_vwv11);
3796
3797   data = smb_base(inbuf) + smb_doff;
3798
3799   /* If this fails we need to send an SMBwriteC response,
3800      not an SMBwritebmpx - set this up now so we don't forget */
3801   CVAL(outbuf,smb_com) = SMBwritec;
3802
3803   if (is_locked(fnum,cnum,tcount,startpos))
3804     return(ERROR(ERRDOS,ERRlock));
3805
3806   seek_file(fnum,startpos);
3807   nwritten = write_file(fnum,data,numtowrite);
3808
3809   if(lp_syncalways(SNUM(cnum)) || write_through)
3810     sync_file(fnum);
3811   
3812   if(nwritten < numtowrite)
3813     return(UNIXERROR(ERRHRD,ERRdiskfull));
3814
3815   /* If the maximum to be written to this file
3816      is greater than what we just wrote then set
3817      up a secondary struct to be attached to this
3818      fd, we will use this to cache error messages etc. */
3819   if(tcount > nwritten) 
3820     {
3821       write_bmpx_struct *wbms;
3822       if(Files[fnum].wbmpx_ptr != NULL)
3823         wbms = Files[fnum].wbmpx_ptr; /* Use an existing struct */
3824       else
3825         wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
3826       if(!wbms)
3827         {
3828           DEBUG(0,("Out of memory in reply_readmpx\n"));
3829           return(ERROR(ERRSRV,ERRnoresource));
3830         }
3831       wbms->wr_mode = write_through;
3832       wbms->wr_discard = False; /* No errors yet */
3833       wbms->wr_total_written = nwritten;
3834       wbms->wr_errclass = 0;
3835       wbms->wr_error = 0;
3836       Files[fnum].wbmpx_ptr = wbms;
3837     }
3838
3839   /* We are returning successfully, set the message type back to
3840      SMBwritebmpx */
3841   CVAL(outbuf,smb_com) = SMBwriteBmpx;
3842   
3843   outsize = set_message(outbuf,1,0,True);
3844   
3845   SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
3846   
3847   DEBUG(3,("%s writebmpx fnum=%d cnum=%d num=%d wrote=%d\n",
3848         timestring(),fnum,cnum,numtowrite,nwritten));
3849   
3850   if (write_through && tcount==nwritten) {
3851     /* we need to send both a primary and a secondary response */
3852     smb_setlen(outbuf,outsize - 4);
3853     send_smb(Client,outbuf);
3854
3855     /* now the secondary */
3856     outsize = set_message(outbuf,1,0,True);
3857     CVAL(outbuf,smb_com) = SMBwritec;
3858     SSVAL(outbuf,smb_vwv0,nwritten);
3859   }
3860
3861   return(outsize);
3862 }
3863
3864
3865 /****************************************************************************
3866   reply to a SMBwritebs (write block multiplex secondary) request
3867 ****************************************************************************/
3868 int reply_writebs(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3869 {
3870   int cnum,numtowrite,fnum;
3871   int nwritten = -1;
3872   int outsize = 0;
3873   int32 startpos;
3874   int tcount, write_through, smb_doff;
3875   char *data;
3876   write_bmpx_struct *wbms;
3877   BOOL send_response = False;
3878   
3879   cnum = SVAL(inbuf,smb_tid);
3880   fnum = GETFNUM(inbuf,smb_vwv0);
3881   CHECK_FNUM(fnum,cnum);
3882   CHECK_WRITE(fnum);
3883
3884   tcount = SVAL(inbuf,smb_vwv1);
3885   startpos = IVAL(inbuf,smb_vwv2);
3886   numtowrite = SVAL(inbuf,smb_vwv6);
3887   smb_doff = SVAL(inbuf,smb_vwv7);
3888
3889   data = smb_base(inbuf) + smb_doff;
3890
3891   /* We need to send an SMBwriteC response, not an SMBwritebs */
3892   CVAL(outbuf,smb_com) = SMBwritec;
3893
3894   /* This fd should have an auxiliary struct attached,
3895      check that it does */
3896   wbms = Files[fnum].wbmpx_ptr;
3897   if(!wbms) return(-1);
3898
3899   /* If write through is set we can return errors, else we must
3900      cache them */
3901   write_through = wbms->wr_mode;
3902
3903   /* Check for an earlier error */
3904   if(wbms->wr_discard)
3905     return -1; /* Just discard the packet */
3906
3907   seek_file(fnum,startpos);
3908   nwritten = write_file(fnum,data,numtowrite);
3909
3910   if(lp_syncalways(SNUM(cnum)) || write_through)
3911     sync_file(fnum);
3912   
3913   if (nwritten < numtowrite)
3914     {
3915       if(write_through) {
3916         /* We are returning an error - we can delete the aux struct */
3917         if (wbms) free((char *)wbms);
3918         Files[fnum].wbmpx_ptr = NULL;
3919         return(ERROR(ERRHRD,ERRdiskfull));
3920       }
3921       return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
3922     }
3923
3924   /* Increment the total written, if this matches tcount
3925      we can discard the auxiliary struct (hurrah !) and return a writeC */
3926   wbms->wr_total_written += nwritten;
3927   if(wbms->wr_total_written >= tcount)
3928     {
3929       if (write_through) {
3930         outsize = set_message(outbuf,1,0,True);
3931         SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
3932         send_response = True;
3933       }
3934
3935       free((char *)wbms);
3936       Files[fnum].wbmpx_ptr = NULL;
3937     }
3938
3939   if(send_response)
3940     return(outsize);
3941
3942   return(-1);
3943 }
3944
3945
3946 /****************************************************************************
3947   reply to a SMBsetattrE
3948 ****************************************************************************/
3949 int reply_setattrE(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3950 {
3951   int cnum,fnum;
3952   struct utimbuf unix_times;
3953   int outsize = 0;
3954
3955   outsize = set_message(outbuf,0,0,True);
3956
3957   cnum = SVAL(inbuf,smb_tid);
3958   fnum = GETFNUM(inbuf,smb_vwv0);
3959
3960   CHECK_FNUM(fnum,cnum);
3961   CHECK_ERROR(fnum);
3962
3963   /* Convert the DOS times into unix times. Ignore create
3964      time as UNIX can't set this.
3965      */
3966   unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
3967   unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
3968   
3969   /* 
3970    * Patch from Ray Frush <frush@engr.colostate.edu>
3971    * Sometimes times are sent as zero - ignore them.
3972    */
3973
3974   if ((unix_times.actime == 0) && (unix_times.modtime == 0)) 
3975   {
3976     /* Ignore request */
3977     DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d ignoring zero request - \
3978 not setting timestamps of 0\n",
3979           timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
3980     return(outsize);
3981   }
3982   else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) 
3983   {
3984     /* set modify time = to access time if modify time was 0 */
3985     unix_times.modtime = unix_times.actime;
3986   }
3987
3988   /* Set the date on this file */
3989   if(file_utime(cnum, Files[fnum].name, &unix_times))
3990     return(ERROR(ERRDOS,ERRnoaccess));
3991   
3992   DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d actime=%d modtime=%d\n",
3993     timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
3994
3995   return(outsize);
3996 }
3997
3998
3999 /****************************************************************************
4000   reply to a SMBgetattrE
4001 ****************************************************************************/
4002 int reply_getattrE(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4003 {
4004   int cnum,fnum;
4005   struct stat sbuf;
4006   int outsize = 0;
4007   int mode;
4008
4009   outsize = set_message(outbuf,11,0,True);
4010
4011   cnum = SVAL(inbuf,smb_tid);
4012   fnum = GETFNUM(inbuf,smb_vwv0);
4013
4014   CHECK_FNUM(fnum,cnum);
4015   CHECK_ERROR(fnum);
4016
4017   /* Do an fstat on this file */
4018   if(fstat(Files[fnum].fd_ptr->fd, &sbuf))
4019     return(UNIXERROR(ERRDOS,ERRnoaccess));
4020   
4021   mode = dos_mode(cnum,Files[fnum].name,&sbuf);
4022   
4023   /* Convert the times into dos times. Set create
4024      date to be last modify date as UNIX doesn't save
4025      this */
4026   put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(cnum))));
4027   put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
4028   put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
4029   if (mode & aDIR)
4030     {
4031       SIVAL(outbuf,smb_vwv6,0);
4032       SIVAL(outbuf,smb_vwv8,0);
4033     }
4034   else
4035     {
4036       SIVAL(outbuf,smb_vwv6,sbuf.st_size);
4037       SIVAL(outbuf,smb_vwv8,ROUNDUP(sbuf.st_size,1024));
4038     }
4039   SSVAL(outbuf,smb_vwv10, mode);
4040   
4041   DEBUG(3,("%s reply_getattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
4042   
4043   return(outsize);
4044 }