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