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