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