fix bug #7; bad offset when retreiving the lanman string
[Samba.git] / source / smbd / reply.c
bloba723b2056580288e3fe681c7b78ebf8fa580268e
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Main SMB reply routines
5 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
22 This file handles most of the reply_ calls that the server
23 makes to handle specific protocols
27 #include "includes.h"
29 /* look in server.c for some explanation of these variables */
30 extern int Protocol;
31 extern int max_send;
32 extern int max_recv;
33 extern char magic_char;
34 extern BOOL case_sensitive;
35 extern BOOL case_preserve;
36 extern BOOL short_case_preserve;
37 extern userdom_struct current_user_info;
38 extern pstring global_myname;
39 extern fstring global_myworkgroup;
40 extern int global_oplock_break;
41 uint32 global_client_caps = 0;
42 unsigned int smb_echo_count = 0;
44 /****************************************************************************
45 Report a possible attack via the password buffer overflow bug.
46 ****************************************************************************/
48 static void overflow_attack(int len)
50 if( DEBUGLVL( 0 ) ) {
51 dbgtext( "ERROR: Invalid password length %d.\n", len );
52 dbgtext( "Your machine may be under attack by someone " );
53 dbgtext( "attempting to exploit an old bug.\n" );
54 dbgtext( "Attack was from IP = %s.\n", client_addr() );
59 /****************************************************************************
60 Reply to an special message.
61 ****************************************************************************/
63 int reply_special(char *inbuf,char *outbuf)
65 int outsize = 4;
66 int msg_type = CVAL(inbuf,0);
67 int msg_flags = CVAL(inbuf,1);
68 pstring name1,name2;
69 extern fstring remote_machine;
70 extern fstring local_machine;
71 int len;
72 char name_type = 0;
74 *name1 = *name2 = 0;
76 memset(outbuf,'\0',smb_size);
78 smb_setlen(outbuf,0);
80 switch (msg_type) {
81 case 0x81: /* session request */
82 SCVAL(outbuf,0,0x82);
83 SCVAL(outbuf,3,0);
84 if (name_len(inbuf+4) > 50 ||
85 name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
86 DEBUG(0,("Invalid name length in session request\n"));
87 return(0);
89 name_extract(inbuf,4,name1);
90 name_extract(inbuf,4 + name_len(inbuf + 4),name2);
91 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
92 name1,name2));
94 fstrcpy(remote_machine,name2);
95 remote_machine[15] = 0;
96 trim_string(remote_machine," "," ");
97 strlower(remote_machine);
98 alpha_strcpy(remote_machine,remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1);
100 fstrcpy(local_machine,name1);
101 len = strlen(local_machine);
102 if (len == 16) {
103 name_type = local_machine[15];
104 local_machine[15] = 0;
106 trim_string(local_machine," "," ");
107 strlower(local_machine);
108 alpha_strcpy(local_machine,local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1);
110 DEBUG(2,("netbios connect: local=%s remote=%s\n",
111 local_machine, remote_machine ));
113 if (name_type == 'R') {
114 /* We are being asked for a pathworks session ---
115 no thanks! */
116 SCVAL(outbuf, 0, 0x83);
117 break;
120 /* add it as a possible user name if we
121 are in share mode security */
122 if (lp_security() == SEC_SHARE) {
123 add_session_user(remote_machine);
126 reload_services(True);
127 reopen_logs();
129 if (lp_status(-1))
130 claim_connection(NULL,"",0,True);
132 break;
134 case 0x89: /* session keepalive request
135 (some old clients produce this?) */
136 SCVAL(outbuf,0,0x85);
137 SCVAL(outbuf,3,0);
138 break;
140 case 0x82: /* positive session response */
141 case 0x83: /* negative session response */
142 case 0x84: /* retarget session response */
143 DEBUG(0,("Unexpected session response\n"));
144 break;
146 case 0x85: /* session keepalive */
147 default:
148 return(0);
151 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
152 msg_type, msg_flags));
154 return(outsize);
157 /*******************************************************************
158 Work out what error to give to a failed connection.
159 ********************************************************************/
161 static int connection_error(char *outbuf, int ecode)
163 if (ecode == ERRnoipc || ecode == ERRnosuchshare)
164 return(ERROR_DOS(ERRDOS,ecode));
166 return(ERROR_DOS(ERRSRV,ecode));
169 /****************************************************************************
170 Parse a share descriptor string.
171 ****************************************************************************/
173 static void parse_connect(char *p,char *service,char *user,
174 char *password,int *pwlen,char *dev)
176 char *p2;
178 DEBUG(4,("parsing connect string %s\n",p));
180 p2 = strrchr(p,'\\');
181 if (p2 == NULL)
182 fstrcpy(service,p);
183 else
184 fstrcpy(service,p2+1);
186 p += strlen(p) + 2;
188 fstrcpy(password,p);
189 *pwlen = strlen(password);
191 p += strlen(p) + 2;
193 fstrcpy(dev,p);
195 *user = 0;
196 p = strchr(service,'%');
197 if (p != NULL)
199 *p = 0;
200 fstrcpy(user,p+1);
204 /****************************************************************************
205 Reply to a tcon.
206 ****************************************************************************/
208 int reply_tcon(connection_struct *conn,
209 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
211 BOOL doencrypt = SMBENCRYPT();
212 pstring service;
213 pstring user;
214 pstring password;
215 pstring dev;
216 int outsize = 0;
217 uint16 vuid = SVAL(inbuf,smb_uid);
218 int pwlen=0;
219 int ecode = -1;
220 START_PROFILE(SMBtcon);
222 *service = *user = *password = *dev = 0;
224 parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
227 * If the vuid is valid, we should be using that....
230 if (*user == '\0' && (lp_security() != SEC_SHARE) && validated_username(vuid)) {
231 pstrcpy(user,validated_username(vuid));
235 * Ensure the user and password names are in UNIX codepage format.
238 pstrcpy(user,dos_to_unix_static(user));
239 if (!doencrypt)
240 pstrcpy(password,dos_to_unix_static(password));
243 * Pass the user through the NT -> unix user mapping
244 * function.
247 (void)map_username(user);
250 * Do any UNIX username case mangling.
252 (void)Get_Pwnam( user, True);
254 conn = make_connection(service,user,password,pwlen,dev,vuid,&ecode);
256 if (!conn) {
257 END_PROFILE(SMBtcon);
258 return(connection_error(outbuf,ecode));
261 outsize = set_message(outbuf,2,0,True);
262 SSVAL(outbuf,smb_vwv0,max_recv);
263 SSVAL(outbuf,smb_vwv1,conn->cnum);
264 SSVAL(outbuf,smb_tid,conn->cnum);
266 DEBUG(3,("tcon service=%s user=%s cnum=%d\n",
267 service, user, conn->cnum));
269 END_PROFILE(SMBtcon);
270 return(outsize);
273 /****************************************************************************
274 Reply to a tcon and X.
275 ****************************************************************************/
277 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
279 fstring service;
280 pstring user;
281 pstring password;
282 pstring devicename;
283 BOOL doencrypt = SMBENCRYPT();
284 int ecode = -1;
285 uint16 vuid = SVAL(inbuf,smb_uid);
286 int passlen = SVAL(inbuf,smb_vwv3);
287 char *path;
288 char *p;
289 START_PROFILE(SMBtconX);
291 *service = *user = *password = *devicename = 0;
293 /* we might have to close an old one */
294 if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
295 close_cnum(conn,vuid);
298 if (passlen > MAX_PASS_LEN) {
299 overflow_attack(passlen);
300 return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
303 memcpy(password,smb_buf(inbuf),passlen);
304 password[passlen]=0;
305 path = smb_buf(inbuf) + passlen;
307 if (passlen != 24) {
308 if (strequal(password," "))
309 *password = 0;
310 passlen = strlen(password);
314 * the service name can be either: \\server\share
315 * or share directly like on the DELL PowerVault 705
317 if (*path=='\\') {
318 p = strchr(path+2,'\\');
319 if (!p) {
320 END_PROFILE(SMBtconX);
321 return(ERROR_DOS(ERRDOS,ERRnosuchshare));
323 fstrcpy(service,p+1);
325 else
326 fstrcpy(service,path);
328 p = strchr(service,'%');
329 if (p) {
330 *p++ = 0;
331 fstrcpy(user,p);
333 StrnCpy(devicename,path + strlen(path) + 1,6);
334 DEBUG(4,("Got device type %s\n",devicename));
337 * If the vuid is valid, we should be using that....
340 if (*user == '\0' && (lp_security() != SEC_SHARE) && validated_username(vuid)) {
341 pstrcpy(user,validated_username(vuid));
345 * Ensure the user and password names are in UNIX codepage format.
348 pstrcpy(user,dos_to_unix_static(user));
349 if (!doencrypt)
350 pstrcpy(password,dos_to_unix_static(password));
353 * Pass the user through the NT -> unix user mapping
354 * function.
357 (void)map_username(user);
360 * Do any UNIX username case mangling.
362 (void)Get_Pwnam(user, True);
364 conn = make_connection(service,user,password,passlen,devicename,vuid,&ecode);
366 if (!conn) {
367 END_PROFILE(SMBtconX);
368 return(connection_error(outbuf,ecode));
371 if (Protocol < PROTOCOL_NT1) {
372 set_message(outbuf,2,strlen(devicename)+1,True);
373 pstrcpy(smb_buf(outbuf),devicename);
374 } else {
375 char *fsname = lp_fstype(SNUM(conn));
377 set_message(outbuf,3,3,True);
379 p = smb_buf(outbuf);
380 pstrcpy(p,devicename); p = skip_string(p,1); /* device name */
381 pstrcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
383 set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
385 /* what does setting this bit do? It is set by NT4 and
386 may affect the ability to autorun mounted cdroms */
387 SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
388 (lp_csc_policy(SNUM(conn)) << 2));
390 init_dfsroot(conn, inbuf, outbuf);
394 DEBUG(3,("tconX service=%s user=%s\n",
395 service, user));
397 /* set the incoming and outgoing tid to the just created one */
398 SSVAL(inbuf,smb_tid,conn->cnum);
399 SSVAL(outbuf,smb_tid,conn->cnum);
401 END_PROFILE(SMBtconX);
402 return chain_reply(inbuf,outbuf,length,bufsize);
405 /****************************************************************************
406 Reply to an unknown type.
407 ****************************************************************************/
409 int reply_unknown(char *inbuf,char *outbuf)
411 int type;
412 type = CVAL(inbuf,smb_com);
414 DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
415 smb_fn_name(type), type, type));
417 return(ERROR_DOS(ERRSRV,ERRunknownsmb));
420 /****************************************************************************
421 Reply to an ioctl.
422 ****************************************************************************/
424 int reply_ioctl(connection_struct *conn,
425 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
427 uint16 device = SVAL(inbuf,smb_vwv1);
428 uint16 function = SVAL(inbuf,smb_vwv2);
429 uint32 ioctl_code = (device << 16) + function;
430 int replysize, outsize;
431 char *p;
432 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
433 START_PROFILE(SMBioctl);
435 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
437 switch (ioctl_code)
439 case IOCTL_QUERY_JOB_INFO:
440 replysize = 32;
441 break;
442 default:
443 END_PROFILE(SMBioctl);
444 return(ERROR_DOS(ERRSRV,ERRnosupport));
447 outsize = set_message(outbuf,8,replysize+1,True);
448 SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
449 SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
450 SSVAL(outbuf,smb_vwv6,52); /* Offset to data */
451 p = smb_buf(outbuf) + 1; /* Allow for alignment */
453 switch (ioctl_code)
455 case IOCTL_QUERY_JOB_INFO:
456 SSVAL(p,0,fsp->print_jobid); /* Job number */
457 StrnCpy(p+2, global_myname, 15); /* Our NetBIOS name */
458 StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */
459 break;
462 END_PROFILE(SMBioctl);
463 return outsize;
466 /****************************************************************************
467 Always return an error: it's just a matter of which one...
468 ****************************************************************************/
470 static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user,
471 char *smb_passwd, int smb_passlen,
472 char *smb_nt_passwd, int smb_nt_passlen)
474 SAM_ACCOUNT *sam_trust_acct = NULL; /* check if trust account exists */
475 uint16 acct_ctrl;
477 if (lp_security() == SEC_USER) {
478 pdb_init_sam(&sam_trust_acct);
479 pdb_getsampwnam(sam_trust_acct, user);
480 } else {
481 DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user));
482 return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw));
485 if (sam_trust_acct == NULL) {
486 /* lkclXXXX: workstation entry doesn't exist */
487 DEBUG(0,("session_trust_account: Trust account %s user doesn't exist\n",user));
488 return(ERROR_BOTH(NT_STATUS_NO_SUCH_USER,ERRDOS,1317));
489 } else {
490 if ((smb_passlen != 24) || (smb_nt_passlen != 24)) {
491 DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user));
492 pdb_free_sam(sam_trust_acct);
493 return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw));
496 if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) {
497 DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
498 pdb_free_sam(sam_trust_acct);
499 return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw));
502 acct_ctrl = pdb_get_acct_ctrl(sam_trust_acct);
503 if (acct_ctrl & ACB_DOMTRUST) {
504 DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user));
505 pdb_free_sam(sam_trust_acct);
506 return(ERROR_BOTH(NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT,ERRDOS,1807));
509 if (acct_ctrl & ACB_SVRTRUST) {
510 DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user));
511 pdb_free_sam(sam_trust_acct);
512 return(ERROR_BOTH(NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT,ERRDOS,1809));
515 if (acct_ctrl & ACB_WSTRUST) {
516 DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user));
517 pdb_free_sam(sam_trust_acct);
518 return(ERROR_BOTH(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT,ERRDOS,1808));
522 /* don't know what to do: indicate logon failure */
523 pdb_free_sam(sam_trust_acct);
524 return(ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRDOS,1326));
527 /****************************************************************************
528 Create a UNIX user on demand.
529 ****************************************************************************/
531 int smb_create_user(char *unix_user, char *homedir)
533 pstring add_script;
534 int ret;
536 pstrcpy(add_script, lp_adduser_script());
537 if (! *add_script)
538 return -1;
539 all_string_sub(add_script, "%u", unix_user, sizeof(pstring));
540 if (homedir)
541 all_string_sub(add_script, "%H", homedir, sizeof(pstring));
542 ret = smbrun(add_script,NULL);
543 DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
544 return ret;
547 /****************************************************************************
548 Delete a UNIX user on demand.
549 ****************************************************************************/
551 static int smb_delete_user(char *unix_user)
553 pstring del_script;
554 int ret;
557 * Sanity check -- do not delete 'root' account
560 if (StrCaseCmp("root", unix_user) == 0) {
561 DEBUG(0,("smb_delete_user: Will not delete the [%s] user account!\n", unix_user));
562 return -1;
565 pstrcpy(del_script, lp_deluser_script());
566 if (! *del_script)
567 return -1;
568 all_string_sub(del_script, "%u", unix_user, sizeof(pstring));
569 ret = smbrun(del_script,NULL);
570 DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
571 return ret;
574 /****************************************************************************
575 Check user is in correct domain if required
576 ****************************************************************************/
578 static BOOL check_domain_match(char *user, char *domain)
581 * If we aren't serving to trusted domains, we must make sure that
582 * the validation request comes from an account in the same domain
583 * as the Samba server
586 if (!lp_allow_trusted_domains() &&
587 !strequal(lp_workgroup(), domain) ) {
588 DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
589 return False;
590 } else {
591 return True;
595 /****************************************************************************
596 Check for a valid username and password in security=server mode.
597 ****************************************************************************/
599 static BOOL check_server_security(char *orig_user, char *domain, char *unix_user,
600 char *smb_apasswd, int smb_apasslen,
601 char *smb_ntpasswd, int smb_ntpasslen)
603 BOOL ret = False;
605 if(lp_security() != SEC_SERVER)
606 return False;
608 if (!check_domain_match(orig_user, domain))
609 return False;
611 ret = server_validate(orig_user, domain,
612 smb_apasswd, smb_apasslen,
613 smb_ntpasswd, smb_ntpasslen);
615 if(ret) {
617 * User validated ok against Domain controller.
618 * If the admin wants us to try and create a UNIX
619 * user on the fly, do so.
620 * Note that we can never delete users when in server
621 * level security as we never know if it was a failure
622 * due to a bad password, or the user really doesn't exist.
625 if(lp_adduser_script() && !smb_getpwnam(unix_user,True))
626 smb_create_user(unix_user, NULL);
629 return ret;
632 /****************************************************************************
633 Check for a valid username and password in security=domain mode.
634 ****************************************************************************/
636 static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user,
637 char *smb_apasswd, int smb_apasslen,
638 char *smb_ntpasswd, int smb_ntpasslen, NT_USER_TOKEN **pptoken)
640 BOOL ret = False;
641 BOOL user_exists = True;
642 struct passwd *pwd = NULL;
644 if(lp_security() != SEC_DOMAIN)
645 return False;
647 if (!check_domain_match(orig_user, domain))
648 return False;
650 ret = domain_client_validate(orig_user, domain,
651 smb_apasswd, smb_apasslen,
652 smb_ntpasswd, smb_ntpasslen,
653 &user_exists, pptoken);
655 if(ret) {
657 * User validated ok against Domain controller.
658 * If the admin wants us to try and create a UNIX
659 * user on the fly, do so.
661 if(user_exists && lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) {
662 smb_create_user(unix_user, NULL);
665 if(lp_adduser_script() && pwd) {
666 SMB_STRUCT_STAT st;
669 * Also call smb_create_user if the users home directory
670 * doesn't exist. Used with winbindd to allow the script to
671 * create the home directory for a user mapped with winbindd.
674 if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT))
675 smb_create_user(unix_user, pwd->pw_dir);
678 } else {
680 * User failed to validate ok against Domain controller.
681 * If the failure was "user doesn't exist" and admin
682 * wants us to try and delete that UNIX user on the fly,
683 * do so.
685 if(!user_exists && lp_deluser_script() && smb_getpwnam(unix_user,True)) {
686 smb_delete_user(unix_user);
690 return ret;
693 /****************************************************************************
694 Reply to a session setup command.
695 ****************************************************************************/
697 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
699 int sess_vuid;
700 gid_t gid;
701 uid_t uid;
702 int smb_bufsize;
703 int smb_apasslen = 0;
704 pstring smb_apasswd;
705 int smb_ntpasslen = 0;
706 pstring smb_ntpasswd;
707 BOOL valid_nt_password = False;
708 BOOL valid_lm_password = False;
709 fstring user;
710 fstring orig_user;
711 BOOL guest=False;
712 static BOOL done_sesssetup = False;
713 BOOL doencrypt = SMBENCRYPT();
714 fstring domain;
715 NT_USER_TOKEN *ptok = NULL;
717 START_PROFILE(SMBsesssetupX);
719 *smb_apasswd = 0;
720 *smb_ntpasswd = 0;
721 *domain = 0;
723 smb_bufsize = SVAL(inbuf,smb_vwv2);
725 if (Protocol < PROTOCOL_NT1) {
726 smb_apasslen = SVAL(inbuf,smb_vwv7);
727 if (smb_apasslen > MAX_PASS_LEN) {
728 overflow_attack(smb_apasslen);
729 return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
732 memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
733 smb_apasswd[smb_apasslen] = 0;
734 fstrcpy(user,smb_buf(inbuf)+smb_apasslen);
736 * Incoming user is in DOS codepage format. Convert
737 * to UNIX.
739 fstrcpy(user,dos_to_unix_static(user));
741 if (!doencrypt && (lp_security() != SEC_SERVER)) {
742 smb_apasslen = strlen(smb_apasswd);
744 } else {
745 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
746 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
747 enum remote_arch_types ra_type = get_remote_arch();
748 char *p = smb_buf(inbuf);
749 char *username_str;
750 fstring native_lanman;
753 if(global_client_caps == 0)
754 global_client_caps = IVAL(inbuf,smb_vwv11);
756 /* client_caps is used as final determination if client is NT or Win95.
757 This is needed to return the correct error codes in some
758 circumstances.
761 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
762 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
763 set_remote_arch( RA_WIN95);
767 username_str = smb_buf(inbuf)+smb_apasslen;
768 fstrcpy( native_lanman, skip_string(username_str, 4));
771 * we distinguish between 2K and XP by the "Native Lan Manager"
772 * string.
773 * .NET RC2 => "Windows .NET 5.2"
774 * WinXP => "Windows 2002 5.1"
775 * Win2k => "Windows 2000 5.0"
776 * NT4 => (off by one bug) "Windows NT 4.0"
777 * Win9x => "Windows 4.0"
779 if ( ra_type == RA_WIN2K ) {
780 if ( 0 == strcmp( native_lanman, "Windows 2002 5.1" ) )
781 set_remote_arch( RA_WINXP );
782 else if ( 0 == strcmp( native_lanman, "Windows .NET 5.2" ) )
783 set_remote_arch( RA_WIN2K3 );
786 if (passlen1 != 24 && passlen2 != 24)
787 doencrypt = False;
789 if (passlen1 > MAX_PASS_LEN) {
790 overflow_attack(passlen1);
791 return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
794 passlen1 = MIN(passlen1, MAX_PASS_LEN);
795 passlen2 = MIN(passlen2, MAX_PASS_LEN);
797 if(!doencrypt) {
798 /* both Win95 and WinNT stuff up the password lengths for
799 non-encrypting systems. Uggh.
801 if passlen1==24 its a win95 system, and its setting the
802 password length incorrectly. Luckily it still works with the
803 default code because Win95 will null terminate the password
804 anyway
806 if passlen1>0 and passlen2>0 then maybe its a NT box and its
807 setting passlen2 to some random value which really stuffs
808 things up. we need to fix that one. */
810 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
811 passlen2 = 0;
814 if (lp_restrict_anonymous()) {
815 /* there seems to be no reason behind the differences in MS clients formatting
816 * various info like the domain, NativeOS, and NativeLanMan fields. Win95
817 * in particular seems to have an extra null byte between the username and the
818 * domain, or the password length calculation is wrong, which throws off the
819 * string extraction routines below. This makes the value of domain be the
820 * empty string, which fails the restrict anonymous check further down.
821 * This compensates for that, and allows browsing to work in mixed NT and
822 * win95 environments even when restrict anonymous is true. AAB
824 dump_data(100, p, 0x70);
825 DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2));
826 if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) {
827 DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n"));
828 DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n"));
829 DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n"));
830 passlen1 = 1;
834 if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
835 /* Save the lanman2 password and the NT md4 password. */
836 smb_apasslen = passlen1;
837 memcpy(smb_apasswd,p,smb_apasslen);
838 smb_apasswd[smb_apasslen] = 0;
839 smb_ntpasslen = passlen2;
840 memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
841 smb_ntpasswd[smb_ntpasslen] = 0;
844 * Ensure the plaintext passwords are in UNIX format.
846 if(!doencrypt) {
847 pstrcpy(smb_apasswd,dos_to_unix_static(smb_apasswd));
848 pstrcpy(smb_ntpasswd,dos_to_unix_static(smb_ntpasswd));
851 } else {
852 /* we use the first password that they gave */
853 smb_apasslen = passlen1;
854 StrnCpy(smb_apasswd,p,smb_apasslen);
856 * Ensure the plaintext password is in UNIX format.
858 pstrcpy(smb_apasswd,dos_to_unix_static(smb_apasswd));
860 /* trim the password */
861 smb_apasslen = strlen(smb_apasswd);
863 /* wfwg sometimes uses a space instead of a null */
864 if (strequal(smb_apasswd," ")) {
865 smb_apasslen = 0;
866 *smb_apasswd = 0;
870 p += passlen1 + passlen2;
871 fstrcpy(user,p);
872 p = skip_string(p,1);
874 * Incoming user and domain are in DOS codepage format. Convert
875 * to UNIX.
877 fstrcpy(user,dos_to_unix_static(user));
878 fstrcpy(domain, dos_to_unix_static(p));
879 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
880 domain,skip_string(p,1),skip_string(p,2)));
883 /* don't allow strange characters in usernames or domains */
884 alpha_strcpy(user, user, ". _-$", sizeof(user));
885 alpha_strcpy(domain, domain, ". _-@", sizeof(domain));
886 if (strstr(user, "..") || strstr(domain,"..")) {
887 return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
890 DEBUG(3,("sesssetupX:name=[%s]\n",user));
892 /* If name ends in $ then I think it's asking about whether a */
893 /* computer with that name (minus the $) has access. For now */
894 /* say yes to everything ending in $. */
896 if (*user && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) {
897 END_PROFILE(SMBsesssetupX);
898 return session_trust_account(conn, inbuf, outbuf, user,
899 smb_apasswd, smb_apasslen,
900 smb_ntpasswd, smb_ntpasslen);
903 if (done_sesssetup && lp_restrict_anonymous()) {
904 /* tests show that even if browsing is done over already validated connections
905 * without a username and password the domain is still provided, which it
906 * wouldn't be if it was a purely anonymous connection. So, in order to
907 * restrict anonymous, we only deny connections that have no session
908 * information. If a domain has been provided, then it's not a purely
909 * anonymous connection. AAB
911 if (!*user && !*smb_apasswd && !*domain) {
912 DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
913 END_PROFILE(SMBsesssetupX);
914 return(ERROR_DOS(ERRDOS,ERRnoaccess));
918 /* setup %U substitution */
919 sub_set_smb_name(user);
921 /* If no username is sent use the guest account */
922 if (!*user) {
923 fstrcpy(user,lp_guestaccount(-1));
924 guest = True;
927 fstrcpy(current_user_info.smb_name,user);
929 reload_services(True);
932 * Save the username before mapping. We will use
933 * the original username sent to us for security=server
934 * and security=domain checking.
937 fstrcpy( orig_user, user);
940 * Always try the "DOMAIN\user" lookup first, as this is the most
941 * specific case. If this fails then try the simple "user" lookup.
945 fstring dom_user;
947 /* Work out who's who */
949 slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s",
950 domain, lp_winbind_separator(), user);
952 if (sys_getpwnam(dom_user) != NULL) {
953 fstrcpy(user, dom_user);
954 DEBUG(3,("Using unix username %s\n", dom_user));
959 * Pass the user through the NT -> unix user mapping
960 * function.
963 (void)map_username(user);
966 * Do any UNIX username case mangling.
968 smb_getpwnam(user, True);
970 add_session_user(user);
973 * Check with orig_user for security=server and
974 * security=domain.
977 if (!guest && !check_server_security(orig_user, domain, user,
978 smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen) &&
979 !check_domain_security(orig_user, domain, user, smb_apasswd,
980 smb_apasslen, smb_ntpasswd, smb_ntpasslen, &ptok) &&
981 !check_hosts_equiv(user))
985 * If we get here then the user wasn't guest and the remote
986 * authentication methods failed. Check the authentication
987 * methods on this local server.
989 * If an NT password was supplied try and validate with that
990 * first. This is superior as the passwords are mixed case
991 * 128 length unicode.
994 if(smb_ntpasslen)
996 if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL))
997 DEBUG(2,("NT Password did not match for user '%s'!\n", user));
998 else
999 valid_nt_password = True;
1003 /* check the LanMan password only if necessary and if allowed
1004 by lp_lanman_auth() */
1005 if (!valid_nt_password && lp_lanman_auth())
1007 DEBUG(2,("Defaulting to Lanman password for %s\n", user));
1008 valid_lm_password = password_ok(user, smb_apasswd,smb_apasslen,NULL);
1012 /* The true branch will be executed if
1013 (1) the NT password failed (or was not tried), and
1014 (2) LanMan authentication failed (or was disabled)
1016 if (!valid_nt_password && !valid_lm_password)
1018 if (lp_security() >= SEC_USER)
1020 if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
1022 delete_nt_token(&ptok);
1023 DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
1024 END_PROFILE(SMBsesssetupX);
1025 return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
1028 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
1030 SAM_ACCOUNT *sampass = NULL;
1032 pdb_init_sam(&sampass);
1035 * This is really bad form. We know that password_ok() failed,
1036 * but the return value can't distinguish between a non-existent user
1037 * and a bad password. So we try to look the user up again here
1038 * to see if he or she exists. We must look up the user in the
1039 * "smb passwd file" and not /etc/passwd so that we don't
1040 * get confused when the two don't have a one-to-one correspondence.
1041 * e.g. a standard UNIX account such as "operator" --jerry
1044 if (pdb_getsampwnam(sampass, user))
1046 delete_nt_token(&ptok);
1047 DEBUG(1,("Rejecting user '%s': bad password\n", user));
1048 END_PROFILE(SMBsesssetupX);
1049 pdb_free_sam(sampass);
1050 return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
1053 pdb_free_sam(sampass);
1057 * ..else if lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
1058 * Then always map to guest account - as done below.
1062 if (*smb_apasswd || !smb_getpwnam(user,True))
1063 fstrcpy(user,lp_guestaccount(-1));
1064 DEBUG(3,("Registered username %s for guest access\n",user));
1065 guest = True;
1069 if (!smb_getpwnam(user,True)) {
1070 DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
1071 fstrcpy(user,lp_guestaccount(-1));
1072 guest = True;
1075 if (!strequal(user,lp_guestaccount(-1)) &&
1076 lp_servicenumber(user) < 0)
1078 add_home_service(user,get_user_service_home_dir(user));
1082 /* it's ok - setup a reply */
1083 if (Protocol < PROTOCOL_NT1) {
1084 set_message(outbuf,3,0,True);
1085 } else {
1086 char *p;
1087 set_message(outbuf,3,3,True);
1088 p = smb_buf(outbuf);
1089 pstrcpy(p,"Unix"); p = skip_string(p,1);
1090 pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1);
1091 pstrcpy(p,global_myworkgroup); unix_to_dos(p); p = skip_string(p,1);
1092 set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
1093 /* perhaps grab OS version here?? */
1096 /* Set the correct uid in the outgoing and incoming packets
1097 We will use this on future requests to determine which
1098 user we should become.
1101 const struct passwd *pw = smb_getpwnam(user,False);
1102 if (!pw) {
1103 delete_nt_token(&ptok);
1104 DEBUG(1,("Username %s is invalid on this system\n",user));
1105 END_PROFILE(SMBsesssetupX);
1106 return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw);
1108 gid = pw->pw_gid;
1109 uid = pw->pw_uid;
1112 if (guest)
1113 SSVAL(outbuf,smb_vwv2,1);
1115 /* register the name and uid as being validated, so further connections
1116 to a uid can get through without a password, on the same VC */
1118 sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest,&ptok);
1120 delete_nt_token(&ptok);
1122 if (sess_vuid == -1) {
1123 END_PROFILE(SMBsesssetupX);
1124 return(ERROR_DOS(ERRDOS,ERRnoaccess));
1127 SSVAL(outbuf,smb_uid,sess_vuid);
1128 SSVAL(inbuf,smb_uid,sess_vuid);
1130 if (!done_sesssetup)
1131 max_send = MIN(max_send,smb_bufsize);
1133 DEBUG(6,("Client requested max send size of %d\n", max_send));
1135 done_sesssetup = True;
1137 END_PROFILE(SMBsesssetupX);
1138 return chain_reply(inbuf,outbuf,length,bufsize);
1141 /****************************************************************************
1142 Reply to a chkpth.
1143 ****************************************************************************/
1145 int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1147 int outsize = 0;
1148 int mode;
1149 pstring name;
1150 BOOL ok = False;
1151 BOOL bad_path = False;
1152 SMB_STRUCT_STAT sbuf;
1153 START_PROFILE(SMBchkpth);
1155 pstrcpy(name,smb_buf(inbuf) + 1);
1157 RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
1159 unix_convert(name,conn,0,&bad_path,&sbuf);
1161 mode = SVAL(inbuf,smb_vwv0);
1163 if (check_name(name,conn)) {
1164 if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0)
1165 if (!(ok = S_ISDIR(sbuf.st_mode)))
1166 errno = ENOTDIR;
1170 if (!ok) {
1171 /* We special case this - as when a Windows machine
1172 is parsing a path is steps through the components
1173 one at a time - if a component fails it expects
1174 ERRbadpath, not ERRbadfile.
1176 if(errno == ENOENT) {
1177 return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
1180 return(UNIXERROR(ERRDOS,ERRbadpath));
1183 outsize = set_message(outbuf,0,0,True);
1185 DEBUG(3,("chkpth %s mode=%d\n", name, mode));
1187 END_PROFILE(SMBchkpth);
1188 return(outsize);
1191 /****************************************************************************
1192 Reply to a getatr.
1193 ****************************************************************************/
1195 int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1197 pstring fname;
1198 int outsize = 0;
1199 SMB_STRUCT_STAT sbuf;
1200 BOOL ok = False;
1201 int mode=0;
1202 SMB_OFF_T size=0;
1203 time_t mtime=0;
1204 BOOL bad_path = False;
1205 START_PROFILE(SMBgetatr);
1207 pstrcpy(fname,smb_buf(inbuf) + 1);
1209 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1211 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1212 under WfWg - weird! */
1213 if (! (*fname))
1215 mode = aHIDDEN | aDIR;
1216 if (!CAN_WRITE(conn)) mode |= aRONLY;
1217 size = 0;
1218 mtime = 0;
1219 ok = True;
1221 else
1223 unix_convert(fname,conn,0,&bad_path,&sbuf);
1224 if (check_name(fname,conn))
1226 if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0)
1228 mode = dos_mode(conn,fname,&sbuf);
1229 size = sbuf.st_size;
1230 mtime = sbuf.st_mtime;
1231 if (mode & aDIR)
1232 size = 0;
1233 ok = True;
1235 else
1236 DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
1240 if (!ok)
1242 set_bad_path_error(errno, bad_path);
1243 END_PROFILE(SMBgetatr);
1244 return(UNIXERROR(ERRDOS,ERRbadfile));
1247 outsize = set_message(outbuf,10,0,True);
1249 SSVAL(outbuf,smb_vwv0,mode);
1250 if(lp_dos_filetime_resolution(SNUM(conn)) )
1251 put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
1252 else
1253 put_dos_date3(outbuf,smb_vwv1,mtime);
1254 SIVAL(outbuf,smb_vwv3,(uint32)size);
1256 if (Protocol >= PROTOCOL_NT1)
1257 SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1259 DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
1261 END_PROFILE(SMBgetatr);
1262 return(outsize);
1265 /****************************************************************************
1266 Reply to a setatr.
1267 ****************************************************************************/
1269 int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1271 pstring fname;
1272 int outsize = 0;
1273 BOOL ok=False;
1274 int mode;
1275 time_t mtime;
1276 SMB_STRUCT_STAT sbuf;
1277 BOOL bad_path = False;
1278 START_PROFILE(SMBsetatr);
1280 pstrcpy(fname,smb_buf(inbuf) + 1);
1281 unix_convert(fname,conn,0,&bad_path,&sbuf);
1283 mode = SVAL(inbuf,smb_vwv0);
1284 mtime = make_unix_date3(inbuf+smb_vwv1);
1286 if (VALID_STAT_OF_DIR(sbuf))
1287 mode |= aDIR;
1288 else
1289 mode &= ~aDIR;
1291 if (check_name(fname,conn))
1292 ok = (file_chmod(conn,fname,mode,NULL) == 0);
1293 if (ok)
1294 ok = set_filetime(conn,fname,mtime);
1296 if (!ok)
1298 set_bad_path_error(errno, bad_path);
1299 END_PROFILE(SMBsetatr);
1300 return(UNIXERROR(ERRDOS,ERRnoaccess));
1303 outsize = set_message(outbuf,0,0,True);
1305 DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
1307 END_PROFILE(SMBsetatr);
1308 return(outsize);
1311 /****************************************************************************
1312 Reply to a dskattr.
1313 ****************************************************************************/
1315 int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1317 int outsize = 0;
1318 SMB_BIG_UINT dfree,dsize,bsize;
1319 START_PROFILE(SMBdskattr);
1321 conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
1323 outsize = set_message(outbuf,5,0,True);
1325 if (Protocol <= PROTOCOL_LANMAN2) {
1326 double total_space, free_space;
1327 /* we need to scale this to a number that DOS6 can handle. We
1328 use floating point so we can handle large drives on systems
1329 that don't have 64 bit integers
1331 we end up displaying a maximum of 2G to DOS systems
1333 total_space = dsize * (double)bsize;
1334 free_space = dfree * (double)bsize;
1336 dsize = (total_space+63*512) / (64*512);
1337 dfree = (free_space+63*512) / (64*512);
1339 if (dsize > 0xFFFF) dsize = 0xFFFF;
1340 if (dfree > 0xFFFF) dfree = 0xFFFF;
1342 SSVAL(outbuf,smb_vwv0,dsize);
1343 SSVAL(outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1344 SSVAL(outbuf,smb_vwv2,512); /* and this must be 512 */
1345 SSVAL(outbuf,smb_vwv3,dfree);
1346 } else {
1347 SSVAL(outbuf,smb_vwv0,dsize);
1348 SSVAL(outbuf,smb_vwv1,bsize/512);
1349 SSVAL(outbuf,smb_vwv2,512);
1350 SSVAL(outbuf,smb_vwv3,dfree);
1353 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1355 END_PROFILE(SMBdskattr);
1356 return(outsize);
1359 /****************************************************************************
1360 Reply to a search.
1361 Can be called from SMBsearch, SMBffirst or SMBfunique.
1362 ****************************************************************************/
1364 int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1366 pstring mask;
1367 pstring directory;
1368 pstring fname;
1369 SMB_OFF_T size;
1370 int mode;
1371 time_t date;
1372 int dirtype;
1373 int outsize = 0;
1374 int numentries = 0;
1375 BOOL finished = False;
1376 int maxentries;
1377 int i;
1378 char *p;
1379 BOOL ok = False;
1380 int status_len;
1381 char *path;
1382 char status[21];
1383 int dptr_num= -1;
1384 BOOL check_descend = False;
1385 BOOL expect_close = False;
1386 BOOL can_open = True;
1387 BOOL bad_path = False;
1388 START_PROFILE(SMBsearch);
1390 *mask = *directory = *fname = 0;
1392 /* If we were called as SMBffirst then we must expect close. */
1393 if(CVAL(inbuf,smb_com) == SMBffirst)
1394 expect_close = True;
1396 outsize = set_message(outbuf,1,3,True);
1397 maxentries = SVAL(inbuf,smb_vwv0);
1398 dirtype = SVAL(inbuf,smb_vwv1);
1399 path = smb_buf(inbuf) + 1;
1400 status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
1402 RESOLVE_DFSPATH(path, conn, inbuf, outbuf);
1403 /* dirtype &= ~aDIR; */
1405 if (status_len == 0)
1407 SMB_STRUCT_STAT sbuf;
1408 pstring dir2;
1410 pstrcpy(directory,smb_buf(inbuf)+1);
1411 pstrcpy(dir2,smb_buf(inbuf)+1);
1412 unix_convert(directory,conn,0,&bad_path,&sbuf);
1413 unix_format(dir2);
1415 if (!check_name(directory,conn))
1416 can_open = False;
1418 p = strrchr(dir2,'/');
1419 if (p == NULL)
1421 pstrcpy(mask,dir2);
1422 *dir2 = 0;
1424 else
1426 *p = 0;
1427 pstrcpy(mask,p+1);
1430 p = strrchr(directory,'/');
1431 if (!p)
1432 *directory = 0;
1433 else
1434 *p = 0;
1436 if (strlen(directory) == 0)
1437 pstrcpy(directory,"./");
1438 memset((char *)status,'\0',21);
1439 SCVAL(status,0,(dirtype & 0x1F));
1441 else
1443 int status_dirtype;
1444 memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
1445 status_dirtype = CVAL(status,0) & 0x1F;
1446 if (status_dirtype != (dirtype & 0x1F))
1447 dirtype = status_dirtype;
1448 conn->dirptr = dptr_fetch(status+12,&dptr_num);
1449 if (!conn->dirptr)
1450 goto SearchEmpty;
1451 string_set(&conn->dirpath,dptr_path(dptr_num));
1452 fstrcpy(mask, dptr_wcard(dptr_num));
1455 if (can_open)
1457 p = smb_buf(outbuf) + 3;
1459 ok = True;
1461 if (status_len == 0)
1463 dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
1464 if (dptr_num < 0)
1466 if(dptr_num == -2)
1468 set_bad_path_error(errno, bad_path);
1469 END_PROFILE(SMBsearch);
1470 return (UNIXERROR(ERRDOS,ERRnofids));
1472 END_PROFILE(SMBsearch);
1473 return ERROR_DOS(ERRDOS,ERRnofids);
1475 dptr_set_wcard(dptr_num, strdup(mask));
1476 dptr_set_attr(dptr_num, dirtype);
1477 } else {
1478 dirtype = dptr_attr(dptr_num);
1481 DEBUG(4,("dptr_num is %d\n",dptr_num));
1483 if (ok)
1485 if ((dirtype&0x1F) == aVOLID)
1487 memcpy(p,status,21);
1488 make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
1489 dptr_fill(p+12,dptr_num);
1490 if (dptr_zero(p+12) && (status_len==0))
1491 numentries = 1;
1492 else
1493 numentries = 0;
1494 p += DIR_STRUCT_SIZE;
1496 else
1498 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1499 conn->dirpath,lp_dontdescend(SNUM(conn))));
1500 if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
1501 check_descend = True;
1503 for (i=numentries;(i<maxentries) && !finished;i++)
1505 /* check to make sure we have room in the buffer */
1506 if ( ((PTR_DIFF(p, outbuf))+DIR_STRUCT_SIZE) > BUFFER_SIZE )
1507 break;
1508 finished =
1509 !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
1510 if (!finished)
1512 memcpy(p,status,21);
1513 make_dir_struct(p,mask,fname,size,mode,date);
1514 dptr_fill(p+12,dptr_num);
1515 numentries++;
1517 p += DIR_STRUCT_SIZE;
1520 } /* if (ok ) */
1524 SearchEmpty:
1526 if ( (numentries == 0) || !ok)
1528 SCVAL(outbuf,smb_rcls,ERRDOS);
1529 SSVAL(outbuf,smb_err,ERRnofiles);
1530 dptr_close(&dptr_num);
1533 /* If we were called as SMBffirst with smb_search_id == NULL
1534 and no entries were found then return error and close dirptr
1535 (X/Open spec) */
1537 if(ok && expect_close && numentries == 0 && status_len == 0)
1539 SCVAL(outbuf,smb_rcls,ERRDOS);
1540 SSVAL(outbuf,smb_err,ERRnofiles);
1541 /* Also close the dptr - we know it's gone */
1542 dptr_close(&dptr_num);
1545 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1546 if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
1547 dptr_close(&dptr_num);
1549 SSVAL(outbuf,smb_vwv0,numentries);
1550 SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1551 SCVAL(smb_buf(outbuf),0,5);
1552 SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
1554 if (Protocol >= PROTOCOL_NT1)
1555 SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1557 outsize += DIR_STRUCT_SIZE*numentries;
1558 smb_setlen(outbuf,outsize - 4);
1560 if ((! *directory) && dptr_path(dptr_num))
1561 slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
1563 DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
1564 smb_fn_name(CVAL(inbuf,smb_com)),
1565 mask, directory, dirtype, numentries, maxentries ) );
1567 END_PROFILE(SMBsearch);
1568 return(outsize);
1571 /****************************************************************************
1572 Reply to a fclose (stop directory search).
1573 ****************************************************************************/
1575 int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1577 int outsize = 0;
1578 int status_len;
1579 char *path;
1580 char status[21];
1581 int dptr_num= -2;
1582 START_PROFILE(SMBfclose);
1584 outsize = set_message(outbuf,1,0,True);
1585 path = smb_buf(inbuf) + 1;
1586 status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
1589 if (status_len == 0) {
1590 END_PROFILE(SMBfclose);
1591 return ERROR_DOS(ERRSRV,ERRsrverror);
1594 memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
1596 if(dptr_fetch(status+12,&dptr_num)) {
1597 /* Close the dptr - we know it's gone */
1598 dptr_close(&dptr_num);
1601 SSVAL(outbuf,smb_vwv0,0);
1603 DEBUG(3,("search close\n"));
1605 END_PROFILE(SMBfclose);
1606 return(outsize);
1609 /****************************************************************************
1610 Reply to an open.
1611 ****************************************************************************/
1613 int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1615 pstring fname;
1616 int outsize = 0;
1617 int fmode=0;
1618 int share_mode;
1619 SMB_OFF_T size = 0;
1620 time_t mtime=0;
1621 mode_t unixmode;
1622 int rmode=0;
1623 SMB_STRUCT_STAT sbuf;
1624 BOOL bad_path = False;
1625 files_struct *fsp;
1626 int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1627 START_PROFILE(SMBopen);
1629 share_mode = SVAL(inbuf,smb_vwv0);
1631 pstrcpy(fname,smb_buf(inbuf)+1);
1633 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1635 unix_convert(fname,conn,0,&bad_path,&sbuf);
1637 unixmode = unix_mode(conn,aARCH,fname);
1639 fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1640 unixmode, oplock_request,&rmode,NULL);
1642 if (!fsp)
1644 set_bad_path_error(errno, bad_path);
1645 END_PROFILE(SMBopen);
1646 return(UNIXERROR(ERRDOS,ERRnoaccess));
1649 size = sbuf.st_size;
1650 fmode = dos_mode(conn,fname,&sbuf);
1651 mtime = sbuf.st_mtime;
1653 if (fmode & aDIR) {
1654 DEBUG(3,("attempt to open a directory %s\n",fname));
1655 close_file(fsp,False);
1656 END_PROFILE(SMBopen);
1657 return ERROR_DOS(ERRDOS,ERRnoaccess);
1660 outsize = set_message(outbuf,7,0,True);
1661 SSVAL(outbuf,smb_vwv0,fsp->fnum);
1662 SSVAL(outbuf,smb_vwv1,fmode);
1663 if(lp_dos_filetime_resolution(SNUM(conn)) )
1664 put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
1665 else
1666 put_dos_date3(outbuf,smb_vwv2,mtime);
1667 SIVAL(outbuf,smb_vwv4,(uint32)size);
1668 SSVAL(outbuf,smb_vwv6,rmode);
1670 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1671 SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1674 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1675 SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1676 END_PROFILE(SMBopen);
1677 return(outsize);
1680 /****************************************************************************
1681 Reply to an open and X.
1682 ****************************************************************************/
1684 int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1686 pstring fname;
1687 int smb_mode = SVAL(inbuf,smb_vwv3);
1688 int smb_attr = SVAL(inbuf,smb_vwv5);
1689 /* Breakout the oplock request bits so we can set the
1690 reply bits separately. */
1691 BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
1692 BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1693 BOOL oplock_request = ex_oplock_request | core_oplock_request;
1694 #if 0
1695 int open_flags = SVAL(inbuf,smb_vwv2);
1696 int smb_sattr = SVAL(inbuf,smb_vwv4);
1697 uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
1698 #endif
1699 int smb_ofun = SVAL(inbuf,smb_vwv8);
1700 mode_t unixmode;
1701 SMB_OFF_T size=0;
1702 int fmode=0,mtime=0,rmode=0;
1703 SMB_STRUCT_STAT sbuf;
1704 int smb_action = 0;
1705 BOOL bad_path = False;
1706 files_struct *fsp;
1707 START_PROFILE(SMBopenX);
1709 /* If it's an IPC, pass off the pipe handler. */
1710 if (IS_IPC(conn)) {
1711 if (lp_nt_pipe_support()) {
1712 END_PROFILE(SMBopenX);
1713 return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
1714 } else {
1715 END_PROFILE(SMBopenX);
1716 return ERROR_DOS(ERRSRV,ERRaccess);
1720 /* XXXX we need to handle passed times, sattr and flags */
1722 pstrcpy(fname,smb_buf(inbuf));
1724 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1726 unix_convert(fname,conn,0,&bad_path,&sbuf);
1728 unixmode = unix_mode(conn,smb_attr | aARCH, fname);
1730 fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,unixmode,
1731 oplock_request, &rmode,&smb_action);
1733 if (!fsp)
1735 set_bad_path_error(errno, bad_path);
1736 END_PROFILE(SMBopenX);
1737 return(UNIXERROR(ERRDOS,ERRnoaccess));
1740 size = sbuf.st_size;
1741 fmode = dos_mode(conn,fname,&sbuf);
1742 mtime = sbuf.st_mtime;
1743 if (fmode & aDIR) {
1744 close_file(fsp,False);
1745 END_PROFILE(SMBopenX);
1746 return ERROR_DOS(ERRDOS,ERRnoaccess);
1749 /* If the caller set the extended oplock request bit
1750 and we granted one (by whatever means) - set the
1751 correct bit for extended oplock reply.
1754 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1755 smb_action |= EXTENDED_OPLOCK_GRANTED;
1758 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1759 smb_action |= EXTENDED_OPLOCK_GRANTED;
1762 /* If the caller set the core oplock request bit
1763 and we granted one (by whatever means) - set the
1764 correct bit for core oplock reply.
1767 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1768 SCVAL(outbuf,smb_flg, CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1771 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1772 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1775 set_message(outbuf,15,0,True);
1776 SSVAL(outbuf,smb_vwv2,fsp->fnum);
1777 SSVAL(outbuf,smb_vwv3,fmode);
1778 if(lp_dos_filetime_resolution(SNUM(conn)) )
1779 put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
1780 else
1781 put_dos_date3(outbuf,smb_vwv4,mtime);
1782 SIVAL(outbuf,smb_vwv6,(uint32)size);
1783 SSVAL(outbuf,smb_vwv8,rmode);
1784 SSVAL(outbuf,smb_vwv11,smb_action);
1786 END_PROFILE(SMBopenX);
1787 return chain_reply(inbuf,outbuf,length,bufsize);
1790 /****************************************************************************
1791 Reply to a SMBulogoffX.
1792 ****************************************************************************/
1794 int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1796 uint16 vuid = SVAL(inbuf,smb_uid);
1797 user_struct *vuser = get_valid_user_struct(vuid);
1798 START_PROFILE(SMBulogoffX);
1800 if(vuser == 0) {
1801 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
1804 /* in user level security we are supposed to close any files
1805 open by this user */
1806 if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
1807 file_close_user(vuid);
1810 invalidate_vuid(vuid);
1812 set_message(outbuf,2,0,True);
1814 DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
1816 END_PROFILE(SMBulogoffX);
1817 return chain_reply(inbuf,outbuf,length,bufsize);
1820 /****************************************************************************
1821 Reply to a mknew or a create.
1822 ****************************************************************************/
1824 int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1826 pstring fname;
1827 int com;
1828 int outsize = 0;
1829 int createmode;
1830 mode_t unixmode;
1831 int ofun = 0;
1832 BOOL bad_path = False;
1833 files_struct *fsp;
1834 int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1835 SMB_STRUCT_STAT sbuf;
1836 START_PROFILE(SMBcreate);
1838 com = SVAL(inbuf,smb_com);
1840 createmode = SVAL(inbuf,smb_vwv0);
1841 pstrcpy(fname,smb_buf(inbuf)+1);
1843 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1845 unix_convert(fname,conn,0,&bad_path,&sbuf);
1847 if (createmode & aVOLID) {
1848 DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
1851 unixmode = unix_mode(conn,createmode,fname);
1853 if(com == SMBmknew)
1855 /* We should fail if file exists. */
1856 ofun = FILE_CREATE_IF_NOT_EXIST;
1858 else
1860 /* SMBcreate - Create if file doesn't exist, truncate if it does. */
1861 ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
1864 /* Open file in dos compatibility share mode. */
1865 fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
1866 ofun, unixmode, oplock_request, NULL, NULL);
1868 if (!fsp)
1870 set_bad_path_error(errno, bad_path);
1871 END_PROFILE(SMBcreate);
1872 return(UNIXERROR(ERRDOS,ERRnoaccess));
1875 outsize = set_message(outbuf,1,0,True);
1876 SSVAL(outbuf,smb_vwv0,fsp->fnum);
1878 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1879 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1882 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1883 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1885 DEBUG( 2, ( "new file %s\n", fname ) );
1886 DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
1887 fname, fsp->fd, createmode, (int)unixmode ) );
1889 END_PROFILE(SMBcreate);
1890 return(outsize);
1893 /****************************************************************************
1894 Reply to a create temporary file.
1895 ****************************************************************************/
1897 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1899 pstring fname;
1900 int outsize = 0;
1901 int createmode;
1902 mode_t unixmode;
1903 BOOL bad_path = False;
1904 files_struct *fsp;
1905 int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1906 int tmpfd;
1907 SMB_STRUCT_STAT sbuf;
1908 char *p, *s;
1910 START_PROFILE(SMBctemp);
1912 createmode = SVAL(inbuf,smb_vwv0);
1913 pstrcpy(fname,smb_buf(inbuf)+1);
1914 pstrcat(fname,"\\TMXXXXXX");
1916 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1918 unix_convert(fname,conn,0,&bad_path,&sbuf);
1920 unixmode = unix_mode(conn,createmode,fname);
1922 tmpfd = smb_mkstemp(fname);
1923 if (tmpfd == -1) {
1924 END_PROFILE(SMBctemp);
1925 return(UNIXERROR(ERRDOS,ERRnoaccess));
1928 vfs_stat(conn,fname,&sbuf);
1930 /* Open file in dos compatibility share mode. */
1931 /* We should fail if file does not exist. */
1932 fsp = open_file_shared(conn,fname,&sbuf,
1933 SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
1934 FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST,
1935 unixmode, oplock_request, NULL, NULL);
1936 /* close fd from smb_mkstemp() */
1937 close(tmpfd);
1939 if (!fsp) {
1940 set_bad_path_error(errno, bad_path);
1941 END_PROFILE(SMBctemp);
1942 return(UNIXERROR(ERRDOS,ERRnoaccess));
1945 /* the returned filename is relative to the directory */
1946 s = strrchr(fname, '/');
1947 if (!s)
1948 s = fname;
1949 else
1950 s++;
1952 outsize = set_message(outbuf,1,4+ strlen(fname),True);
1953 SSVAL(outbuf,smb_vwv0,fsp->fnum);
1955 p = smb_buf(outbuf);
1956 SSVALS(p, 0, -1); /* what is this? not in spec */
1957 SSVAL(p, 2, strlen(s));
1958 p += 4;
1959 pstrcpy(p,s);
1961 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1962 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1965 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1966 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1968 DEBUG( 2, ( "created temp file %s\n", fname ) );
1969 DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
1970 fname, fsp->fd, createmode, (int)unixmode ) );
1972 END_PROFILE(SMBctemp);
1973 return(outsize);
1976 /*******************************************************************
1977 Check if a user is allowed to rename a file.
1978 ********************************************************************/
1980 static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst)
1982 int smb_action;
1983 int access_mode;
1984 files_struct *fsp;
1986 if (!CAN_WRITE(conn))
1987 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1989 if (S_ISDIR(pst->st_mode))
1990 return NT_STATUS_OK;
1992 /* We need a better way to return NT status codes from open... */
1993 unix_ERR_class = 0;
1994 unix_ERR_code = 0;
1996 fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
1997 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
1999 if (!fsp) {
2000 NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
2001 if (!NT_STATUS_IS_OK(unix_ERR_ntstatus))
2002 ret = unix_ERR_ntstatus;
2003 else if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
2004 ret = NT_STATUS_SHARING_VIOLATION;
2005 unix_ERR_class = 0;
2006 unix_ERR_code = 0;
2007 unix_ERR_ntstatus = NT_STATUS_OK;
2008 return ret;
2010 close_file(fsp,False);
2011 return NT_STATUS_OK;
2014 /*******************************************************************
2015 Check if a user is allowed to delete a file.
2016 ********************************************************************/
2018 static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
2020 SMB_STRUCT_STAT sbuf;
2021 int fmode;
2022 int smb_action;
2023 int access_mode;
2024 files_struct *fsp;
2026 if (!CAN_WRITE(conn))
2027 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2029 if (conn->vfs_ops.lstat(conn,dos_to_unix_static(fname),&sbuf) != 0)
2030 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2032 fmode = dos_mode(conn,fname,&sbuf);
2033 if (fmode & aDIR)
2034 return NT_STATUS_FILE_IS_A_DIRECTORY;
2035 if (!lp_delete_readonly(SNUM(conn))) {
2036 if (fmode & aRONLY)
2037 return NT_STATUS_CANNOT_DELETE;
2040 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
2041 return NT_STATUS_CANNOT_DELETE;
2043 /* We need a better way to return NT status codes from open... */
2044 unix_ERR_class = 0;
2045 unix_ERR_code = 0;
2047 fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
2048 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
2050 if (!fsp) {
2051 NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
2052 if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
2053 ret = NT_STATUS_SHARING_VIOLATION;
2054 unix_ERR_class = 0;
2055 unix_ERR_code = 0;
2056 return ret;
2058 close_file(fsp,False);
2059 return NT_STATUS_OK;
2062 /****************************************************************************
2063 The guts of the unlink command, split out so it may be called by the NT SMB
2064 code.
2065 ****************************************************************************/
2067 NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
2069 pstring directory;
2070 pstring mask;
2071 char *p;
2072 int count=0;
2073 NTSTATUS error = NT_STATUS_OK;
2074 BOOL has_wild;
2075 BOOL bad_path = False;
2076 BOOL rc = True;
2077 SMB_STRUCT_STAT sbuf;
2079 *directory = *mask = 0;
2081 rc = unix_convert(name,conn,0,&bad_path,&sbuf);
2083 p = strrchr(name,'/');
2084 if (!p) {
2085 pstrcpy(directory,".");
2086 pstrcpy(mask,name);
2087 } else {
2088 *p = 0;
2089 pstrcpy(directory,name);
2090 pstrcpy(mask,p+1);
2094 * We should only check the mangled cache
2095 * here if unix_convert failed. This means
2096 * that the path in 'mask' doesn't exist
2097 * on the file system and so we need to look
2098 * for a possible mangle. This patch from
2099 * Tine Smukavec <valentin.smukavec@hermes.si>.
2102 if (!rc && mangle_is_mangled(mask))
2103 mangle_check_cache( mask );
2105 has_wild = ms_has_wild(mask);
2107 if (!has_wild) {
2108 pstrcat(directory,"/");
2109 pstrcat(directory,mask);
2110 error = can_delete(directory,conn,dirtype);
2111 if (!NT_STATUS_IS_OK(error))
2112 return error;
2114 if (vfs_unlink(conn,directory) == 0)
2115 count++;
2116 } else {
2117 void *dirptr = NULL;
2118 char *dname;
2119 if (check_name(directory,conn))
2120 dirptr = OpenDir(conn, directory, True);
2122 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2123 the pattern matches against the long name, otherwise the short name
2124 We don't implement this yet XXXX
2127 if (dirptr) {
2128 error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2130 if (strequal(mask,"????????.???"))
2131 pstrcpy(mask,"*");
2133 while ((dname = ReadDirName(dirptr))) {
2134 pstring fname;
2135 pstrcpy(fname,dname);
2137 if(!mask_match(fname, mask, case_sensitive))
2138 continue;
2140 slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
2141 error = can_delete(fname,conn,dirtype);
2142 if (!NT_STATUS_IS_OK(error))
2143 continue;
2144 if (vfs_unlink(conn,fname) == 0)
2145 count++;
2146 DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
2148 CloseDir(dirptr);
2152 if (count == 0 && NT_STATUS_IS_OK(error))
2153 error = map_nt_error_from_unix(errno);
2155 return error;
2158 /****************************************************************************
2159 Reply to a unlink
2160 ****************************************************************************/
2162 int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2164 int outsize = 0;
2165 pstring name;
2166 int dirtype;
2167 NTSTATUS status;
2169 START_PROFILE(SMBunlink);
2171 dirtype = SVAL(inbuf,smb_vwv0);
2173 pstrcpy(name,smb_buf(inbuf) + 1);
2175 RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
2177 DEBUG(3,("reply_unlink : %s\n",name));
2179 status = unlink_internals(conn, dirtype, name);
2180 if (!NT_STATUS_IS_OK(status))
2181 return ERROR_NT(status);
2184 * Win2k needs a changenotify request response before it will
2185 * update after a rename..
2188 process_pending_change_notify_queue((time_t)0);
2190 outsize = set_message(outbuf,0,0,True);
2192 END_PROFILE(SMBunlink);
2193 return outsize;
2196 /****************************************************************************
2197 Fail for readbraw.
2198 ****************************************************************************/
2200 void fail_readraw(void)
2202 pstring errstr;
2203 slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
2204 strerror(errno) );
2205 exit_server(errstr);
2208 /****************************************************************************
2209 Use sendfile in readbraw.
2210 ****************************************************************************/
2212 void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread,
2213 ssize_t mincount, char *outbuf)
2215 ssize_t ret=0;
2217 #if defined(WITH_SENDFILE)
2219 * We can only use sendfile on a non-chained packet and on a file
2220 * that is exclusively oplocked. reply_readbraw has already checked the length.
2223 if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) &&
2224 EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && lp_use_sendfile(SNUM(conn)) ) {
2225 DATA_BLOB header;
2227 _smb_setlen(outbuf,nread);
2228 header.data = outbuf;
2229 header.length = 4;
2230 header.free = NULL;
2232 if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) {
2234 * Special hack for broken Linux with no 64 bit clean sendfile. If we
2235 * return ENOSYS then pretend we just got a normal read.
2237 if (errno == ENOSYS)
2238 goto normal_read;
2240 DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
2241 fsp->fsp_name, strerror(errno) ));
2242 exit_server("send_file_readbraw sendfile failed");
2247 normal_read:
2248 #endif
2250 if (nread > 0) {
2251 ret = read_file(fsp,outbuf+4,startpos,nread);
2252 if (ret < mincount)
2253 ret = 0;
2256 _smb_setlen(outbuf,ret);
2257 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
2258 fail_readraw();
2261 /****************************************************************************
2262 Reply to a readbraw (core+ protocol).
2263 ****************************************************************************/
2265 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
2267 extern struct current_user current_user;
2268 ssize_t maxcount,mincount;
2269 size_t nread = 0;
2270 SMB_OFF_T startpos;
2271 char *header = outbuf;
2272 files_struct *fsp;
2273 START_PROFILE(SMBreadbraw);
2276 * Special check if an oplock break has been issued
2277 * and the readraw request croses on the wire, we must
2278 * return a zero length response here.
2281 if(global_oplock_break) {
2282 _smb_setlen(header,0);
2283 if (write_data(smbd_server_fd(),header,4) != 4)
2284 fail_readraw();
2285 DEBUG(5,("readbraw - oplock break finished\n"));
2286 END_PROFILE(SMBreadbraw);
2287 return -1;
2290 fsp = file_fsp(inbuf,smb_vwv0);
2292 if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
2294 * fsp could be NULL here so use the value from the packet. JRA.
2296 DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
2297 _smb_setlen(header,0);
2298 if (write_data(smbd_server_fd(),header,4) != 4)
2299 fail_readraw();
2300 END_PROFILE(SMBreadbraw);
2301 return(-1);
2304 CHECK_FSP(fsp,conn);
2306 flush_write_cache(fsp, READRAW_FLUSH);
2308 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
2309 if(CVAL(inbuf,smb_wct) == 10) {
2311 * This is a large offset (64 bit) read.
2313 #ifdef LARGE_SMB_OFF_T
2315 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
2317 #else /* !LARGE_SMB_OFF_T */
2320 * Ensure we haven't been sent a >32 bit offset.
2323 if(IVAL(inbuf,smb_vwv8) != 0) {
2324 DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
2325 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
2326 _smb_setlen(header,0);
2327 if (write_data(smbd_server_fd(),header,4) != 4)
2328 fail_readraw();
2329 END_PROFILE(SMBreadbraw);
2330 return(-1);
2333 #endif /* LARGE_SMB_OFF_T */
2335 if(startpos < 0) {
2336 DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos ));
2337 _smb_setlen(header,0);
2338 if (write_data(smbd_server_fd(),header,4) != 4)
2339 fail_readraw();
2340 END_PROFILE(SMBreadbraw);
2341 return(-1);
2344 maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
2345 mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
2347 /* ensure we don't overrun the packet size */
2348 maxcount = MIN(65535,maxcount);
2349 maxcount = MAX(mincount,maxcount);
2351 if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
2352 SMB_OFF_T size = fsp->size;
2353 SMB_OFF_T sizeneeded = startpos + maxcount;
2355 if (size < sizeneeded) {
2356 SMB_STRUCT_STAT st;
2357 if (vfs_fstat(fsp,fsp->fd,&st) == 0)
2358 fsp->size = size = st.st_size;
2361 if (startpos >= size)
2362 nread = 0;
2363 else
2364 nread = MIN(maxcount,(size - startpos));
2367 if (nread < mincount)
2368 nread = 0;
2370 DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
2371 (int)maxcount, (int)mincount, (int)nread ) );
2373 send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf);
2375 DEBUG(5,("readbraw finished\n"));
2376 END_PROFILE(SMBreadbraw);
2377 return -1;
2380 /****************************************************************************
2381 Reply to a lockread (core+ protocol).
2382 ****************************************************************************/
2384 int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
2386 ssize_t nread = -1;
2387 char *data;
2388 int outsize = 0;
2389 SMB_OFF_T startpos;
2390 size_t numtoread;
2391 NTSTATUS status;
2392 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2393 START_PROFILE(SMBlockread);
2395 CHECK_FSP(fsp,conn);
2396 CHECK_READ(fsp);
2398 release_level_2_oplocks_on_change(fsp);
2400 numtoread = SVAL(inbuf,smb_vwv1);
2401 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
2403 outsize = set_message(outbuf,5,3,True);
2404 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
2405 data = smb_buf(outbuf) + 3;
2408 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
2409 * protocol request that predates the read/write lock concept.
2410 * Thus instead of asking for a read lock here we need to ask
2411 * for a write lock. JRA.
2414 status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid),
2415 (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
2417 if (NT_STATUS_V(status)) {
2418 if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
2420 * A blocking lock was requested. Package up
2421 * this smb into a queued request and push it
2422 * onto the blocking lock queue.
2424 if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)startpos,
2425 (SMB_BIG_UINT)numtoread)) {
2426 END_PROFILE(SMBlockread);
2427 return -1;
2430 END_PROFILE(SMBlockread);
2431 return ERROR_NT(status);
2434 nread = read_file(fsp,data,startpos,numtoread);
2436 if (nread < 0) {
2437 END_PROFILE(SMBlockread);
2438 return(UNIXERROR(ERRDOS,ERRnoaccess));
2441 outsize += nread;
2442 SSVAL(outbuf,smb_vwv0,nread);
2443 SSVAL(outbuf,smb_vwv5,nread+3);
2444 SSVAL(smb_buf(outbuf),1,nread);
2446 DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
2447 fsp->fnum, (int)numtoread, (int)nread ) );
2449 END_PROFILE(SMBlockread);
2450 return(outsize);
2453 /****************************************************************************
2454 Reply to a read.
2455 ****************************************************************************/
2457 int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2459 size_t numtoread;
2460 ssize_t nread = 0;
2461 char *data;
2462 SMB_OFF_T startpos;
2463 int outsize = 0;
2464 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2465 START_PROFILE(SMBread);
2467 CHECK_FSP(fsp,conn);
2468 CHECK_READ(fsp);
2470 numtoread = SVAL(inbuf,smb_vwv1);
2471 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
2473 outsize = set_message(outbuf,5,3,True);
2474 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
2475 data = smb_buf(outbuf) + 3;
2477 if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
2478 END_PROFILE(SMBread);
2479 return ERROR_DOS(ERRDOS,ERRlock);
2482 if (numtoread > 0)
2483 nread = read_file(fsp,data,startpos,numtoread);
2485 if (nread < 0) {
2486 END_PROFILE(SMBread);
2487 return(UNIXERROR(ERRDOS,ERRnoaccess));
2490 outsize += nread;
2491 SSVAL(outbuf,smb_vwv0,nread);
2492 SSVAL(outbuf,smb_vwv5,nread+3);
2493 SCVAL(smb_buf(outbuf),0,1);
2494 SSVAL(smb_buf(outbuf),1,nread);
2496 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
2497 fsp->fnum, (int)numtoread, (int)nread ) );
2499 END_PROFILE(SMBread);
2500 return(outsize);
2503 /****************************************************************************
2504 Reply to a read and X - possibly using sendfile.
2505 ****************************************************************************/
2507 int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length,
2508 files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
2510 ssize_t nread = -1;
2511 char *data = smb_buf(outbuf);
2513 #if defined(WITH_SENDFILE)
2515 * We can only use sendfile on a non-chained packet and on a file
2516 * that is exclusively oplocked.
2519 if ((CVAL(inbuf,smb_vwv0) == 0xFF) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) &&
2520 lp_use_sendfile(SNUM(conn)) && (lp_write_cache_size(SNUM(conn)) == 0) ) {
2521 SMB_STRUCT_STAT sbuf;
2522 DATA_BLOB header;
2524 if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1)
2525 return(UNIXERROR(ERRDOS,ERRnoaccess));
2527 if (startpos > sbuf.st_size)
2528 goto normal_read;
2530 if (smb_maxcnt > (sbuf.st_size - startpos))
2531 smb_maxcnt = (sbuf.st_size - startpos);
2533 if (smb_maxcnt == 0)
2534 goto normal_read;
2537 * Set up the packet header before send. We
2538 * assume here the sendfile will work (get the
2539 * correct amount of data).
2542 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
2543 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
2544 SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
2545 SCVAL(outbuf,smb_vwv0,0xFF);
2546 set_message(outbuf,12,smb_maxcnt,False);
2547 header.data = outbuf;
2548 header.length = data - outbuf;
2549 header.free = NULL;
2551 if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) {
2553 * Special hack for broken Linux with no 64 bit clean sendfile. If we
2554 * return ENOSYS then pretend we just got a normal read.
2556 if (errno == ENOSYS)
2557 goto normal_read;
2559 DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
2560 fsp->fsp_name, strerror(errno) ));
2561 exit_server("send_file_readX sendfile failed");
2564 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
2565 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
2566 return -1;
2569 normal_read:
2571 #endif
2573 nread = read_file(fsp,data,startpos,smb_maxcnt);
2575 if (nread < 0) {
2576 END_PROFILE(SMBreadX);
2577 return(UNIXERROR(ERRDOS,ERRnoaccess));
2580 SSVAL(outbuf,smb_vwv5,nread);
2581 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
2582 SSVAL(smb_buf(outbuf),-2,nread);
2584 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
2585 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
2587 return nread;
2590 /****************************************************************************
2591 Reply to a read and X.
2592 ****************************************************************************/
2594 int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
2596 files_struct *fsp = file_fsp(inbuf,smb_vwv2);
2597 SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
2598 size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
2599 #if 0
2600 size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
2601 #endif
2602 ssize_t nread = -1;
2603 char *data;
2604 START_PROFILE(SMBreadX);
2606 /* If it's an IPC, pass off the pipe handler. */
2607 if (IS_IPC(conn)) {
2608 END_PROFILE(SMBreadX);
2609 return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
2612 CHECK_FSP(fsp,conn);
2613 CHECK_READ(fsp);
2615 set_message(outbuf,12,0,True);
2616 data = smb_buf(outbuf);
2618 if(CVAL(inbuf,smb_wct) == 12) {
2619 #ifdef LARGE_SMB_OFF_T
2621 * This is a large offset (64 bit) read.
2623 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
2625 #else /* !LARGE_SMB_OFF_T */
2628 * Ensure we haven't been sent a >32 bit offset.
2631 if(IVAL(inbuf,smb_vwv10) != 0) {
2632 DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
2633 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
2634 END_PROFILE(SMBreadX);
2635 return ERROR_DOS(ERRDOS,ERRbadaccess);
2638 #endif /* LARGE_SMB_OFF_T */
2642 if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
2643 END_PROFILE(SMBreadX);
2644 return ERROR_DOS(ERRDOS,ERRlock);
2646 nread = send_file_readX(conn, inbuf, outbuf, length, fsp, startpos, smb_maxcnt);
2647 if (nread != -1)
2648 nread = chain_reply(inbuf,outbuf,length,bufsize);
2650 END_PROFILE(SMBreadX);
2651 return nread;
2654 /****************************************************************************
2655 Reply to a writebraw (core+ or LANMAN1.0 protocol).
2656 ****************************************************************************/
2658 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2660 ssize_t nwritten=0;
2661 ssize_t total_written=0;
2662 size_t numtowrite=0;
2663 size_t tcount;
2664 SMB_OFF_T startpos;
2665 char *data=NULL;
2666 BOOL write_through;
2667 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2668 int outsize = 0;
2669 START_PROFILE(SMBwritebraw);
2671 CHECK_FSP(fsp,conn);
2672 CHECK_WRITE(fsp);
2674 tcount = IVAL(inbuf,smb_vwv1);
2675 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
2676 write_through = BITSETW(inbuf+smb_vwv7,0);
2678 /* We have to deal with slightly different formats depending
2679 on whether we are using the core+ or lanman1.0 protocol */
2681 if(Protocol <= PROTOCOL_COREPLUS) {
2682 numtowrite = SVAL(smb_buf(inbuf),-2);
2683 data = smb_buf(inbuf);
2684 } else {
2685 numtowrite = SVAL(inbuf,smb_vwv10);
2686 data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
2689 /* force the error type */
2690 SCVAL(inbuf,smb_com,SMBwritec);
2691 SCVAL(outbuf,smb_com,SMBwritec);
2693 if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2694 END_PROFILE(SMBwritebraw);
2695 return(ERROR_DOS(ERRDOS,ERRlock));
2698 if (numtowrite>0)
2699 nwritten = write_file(fsp,data,startpos,numtowrite);
2701 DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
2702 fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
2704 if (nwritten < (ssize_t)numtowrite) {
2705 END_PROFILE(SMBwritebraw);
2706 return(UNIXERROR(ERRHRD,ERRdiskfull));
2709 total_written = nwritten;
2711 /* Return a message to the redirector to tell it to send more bytes */
2712 SCVAL(outbuf,smb_com,SMBwritebraw);
2713 SSVALS(outbuf,smb_vwv0,-1);
2714 outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
2715 if (!send_smb(smbd_server_fd(),outbuf))
2716 exit_server("reply_writebraw: send_smb failed.");
2718 /* Now read the raw data into the buffer and write it */
2719 if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
2720 exit_server("secondary writebraw failed");
2723 /* Even though this is not an smb message, smb_len returns the generic length of an smb message */
2724 numtowrite = smb_len(inbuf);
2726 /* Set up outbuf to return the correct return */
2727 outsize = set_message(outbuf,1,0,True);
2728 SCVAL(outbuf,smb_com,SMBwritec);
2729 SSVAL(outbuf,smb_vwv0,total_written);
2731 if (numtowrite != 0) {
2733 if (numtowrite > BUFFER_SIZE) {
2734 DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n",
2735 (unsigned int)numtowrite ));
2736 exit_server("secondary writebraw failed");
2739 if (tcount > nwritten+numtowrite) {
2740 DEBUG(3,("Client overestimated the write %d %d %d\n",
2741 (int)tcount,(int)nwritten,(int)numtowrite));
2744 if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) {
2745 DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n",
2746 strerror(errno) ));
2747 exit_server("secondary writebraw failed");
2750 nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
2752 if (nwritten < (ssize_t)numtowrite) {
2753 SCVAL(outbuf,smb_rcls,ERRHRD);
2754 SSVAL(outbuf,smb_err,ERRdiskfull);
2757 if (nwritten > 0)
2758 total_written += nwritten;
2761 if ((lp_syncalways(SNUM(conn)) || write_through) && lp_strict_sync(SNUM(conn)))
2762 sync_file(conn,fsp);
2764 DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
2765 fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
2767 /* we won't return a status if write through is not selected - this follows what WfWg does */
2768 END_PROFILE(SMBwritebraw);
2769 if (!write_through && total_written==tcount) {
2771 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
2772 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA.
2774 if (!send_keepalive(smbd_server_fd()))
2775 exit_server("reply_writebraw: send of keepalive failed");
2776 return(-1);
2779 return(outsize);
2782 /****************************************************************************
2783 Reply to a writeunlock (core+).
2784 ****************************************************************************/
2786 int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2788 ssize_t nwritten = -1;
2789 size_t numtowrite;
2790 SMB_OFF_T startpos;
2791 char *data;
2792 NTSTATUS status;
2793 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2794 int outsize = 0;
2795 START_PROFILE(SMBwriteunlock);
2797 CHECK_FSP(fsp,conn);
2798 CHECK_WRITE(fsp);
2800 numtowrite = SVAL(inbuf,smb_vwv1);
2801 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
2802 data = smb_buf(inbuf) + 3;
2804 if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos,
2805 WRITE_LOCK,False)) {
2806 END_PROFILE(SMBwriteunlock);
2807 return ERROR_DOS(ERRDOS,ERRlock);
2810 /* The special X/Open SMB protocol handling of
2811 zero length writes is *NOT* done for
2812 this call */
2813 if(numtowrite == 0)
2814 nwritten = 0;
2815 else
2816 nwritten = write_file(fsp,data,startpos,numtowrite);
2818 if (lp_syncalways(SNUM(conn)))
2819 sync_file(conn,fsp);
2821 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
2822 END_PROFILE(SMBwriteunlock);
2823 return(UNIXERROR(ERRHRD,ERRdiskfull));
2826 status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite,
2827 (SMB_BIG_UINT)startpos);
2828 if (NT_STATUS_V(status)) {
2829 END_PROFILE(SMBwriteunlock);
2830 return ERROR_NT(status);
2833 outsize = set_message(outbuf,1,0,True);
2835 SSVAL(outbuf,smb_vwv0,nwritten);
2837 DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
2838 fsp->fnum, (int)numtowrite, (int)nwritten ) );
2840 END_PROFILE(SMBwriteunlock);
2841 return(outsize);
2844 /****************************************************************************
2845 Reply to a write.
2846 ****************************************************************************/
2848 int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
2850 size_t numtowrite;
2851 ssize_t nwritten = -1;
2852 SMB_OFF_T startpos;
2853 char *data;
2854 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2855 int outsize = 0;
2856 START_PROFILE(SMBwrite);
2858 /* If it's an IPC, pass off the pipe handler. */
2859 if (IS_IPC(conn)) {
2860 END_PROFILE(SMBwrite);
2861 return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
2864 CHECK_FSP(fsp,conn);
2865 CHECK_WRITE(fsp);
2867 numtowrite = SVAL(inbuf,smb_vwv1);
2868 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
2869 data = smb_buf(inbuf) + 3;
2871 if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2872 END_PROFILE(SMBwrite);
2873 return ERROR_DOS(ERRDOS,ERRlock);
2877 * X/Open SMB protocol says that if smb_vwv1 is
2878 * zero then the file size should be extended or
2879 * truncated to the size given in smb_vwv[2-3].
2882 if(numtowrite == 0) {
2884 * This is actually an allocate call, and set EOF. JRA.
2886 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
2887 if (nwritten < 0) {
2888 END_PROFILE(SMBwrite);
2889 return ERROR_NT(NT_STATUS_DISK_FULL);
2891 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
2892 if (nwritten < 0) {
2893 END_PROFILE(SMBwrite);
2894 return ERROR_NT(NT_STATUS_DISK_FULL);
2896 } else
2897 nwritten = write_file(fsp,data,startpos,numtowrite);
2899 if (lp_syncalways(SNUM(conn)))
2900 sync_file(conn,fsp);
2902 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
2903 END_PROFILE(SMBwrite);
2904 return(UNIXERROR(ERRHRD,ERRdiskfull));
2907 outsize = set_message(outbuf,1,0,True);
2909 SSVAL(outbuf,smb_vwv0,nwritten);
2911 if (nwritten < (ssize_t)numtowrite) {
2912 SCVAL(outbuf,smb_rcls,ERRHRD);
2913 SSVAL(outbuf,smb_err,ERRdiskfull);
2916 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
2918 END_PROFILE(SMBwrite);
2919 return(outsize);
2922 /****************************************************************************
2923 Reply to a write and X.
2924 ****************************************************************************/
2926 int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
2928 files_struct *fsp = file_fsp(inbuf,smb_vwv2);
2929 SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
2930 size_t numtowrite = SVAL(inbuf,smb_vwv10);
2931 BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
2932 ssize_t nwritten = -1;
2933 unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
2934 unsigned int smblen = smb_len(inbuf);
2935 char *data;
2936 BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
2937 START_PROFILE(SMBwriteX);
2939 /* If it's an IPC, pass off the pipe handler. */
2940 if (IS_IPC(conn)) {
2941 END_PROFILE(SMBwriteX);
2942 return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
2945 CHECK_FSP(fsp,conn);
2946 CHECK_WRITE(fsp);
2948 /* Deal with possible LARGE_WRITEX */
2949 if (large_writeX)
2950 numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
2952 if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
2953 END_PROFILE(SMBwriteX);
2954 return ERROR_DOS(ERRDOS,ERRbadmem);
2957 data = smb_base(inbuf) + smb_doff;
2959 if(CVAL(inbuf,smb_wct) == 14) {
2960 #ifdef LARGE_SMB_OFF_T
2962 * This is a large offset (64 bit) write.
2964 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
2966 #else /* !LARGE_SMB_OFF_T */
2969 * Ensure we haven't been sent a >32 bit offset.
2972 if(IVAL(inbuf,smb_vwv12) != 0) {
2973 DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
2974 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
2975 END_PROFILE(SMBwriteX);
2976 return ERROR_DOS(ERRDOS,ERRbadaccess);
2979 #endif /* LARGE_SMB_OFF_T */
2982 if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2983 END_PROFILE(SMBwriteX);
2984 return ERROR_DOS(ERRDOS,ERRlock);
2987 /* X/Open SMB protocol says that, unlike SMBwrite
2988 if the length is zero then NO truncation is
2989 done, just a write of zero. To truncate a file,
2990 use SMBwrite. */
2991 if(numtowrite == 0)
2992 nwritten = 0;
2993 else
2994 nwritten = write_file(fsp,data,startpos,numtowrite);
2996 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
2997 END_PROFILE(SMBwriteX);
2998 return(UNIXERROR(ERRHRD,ERRdiskfull));
3001 set_message(outbuf,6,0,True);
3003 SSVAL(outbuf,smb_vwv2,nwritten);
3004 if (large_writeX)
3005 SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
3007 if (nwritten < (ssize_t)numtowrite) {
3008 SCVAL(outbuf,smb_rcls,ERRHRD);
3009 SSVAL(outbuf,smb_err,ERRdiskfull);
3012 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
3013 fsp->fnum, (int)numtowrite, (int)nwritten));
3015 if (lp_syncalways(SNUM(conn)) || write_through)
3016 sync_file(conn,fsp);
3018 END_PROFILE(SMBwriteX);
3019 return chain_reply(inbuf,outbuf,length,bufsize);
3023 /****************************************************************************
3024 Reply to a lseek.
3025 ****************************************************************************/
3027 int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
3029 SMB_OFF_T startpos;
3030 SMB_OFF_T res= -1;
3031 int mode,umode;
3032 int outsize = 0;
3033 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3034 START_PROFILE(SMBlseek);
3036 CHECK_FSP(fsp,conn);
3038 flush_write_cache(fsp, SEEK_FLUSH);
3040 mode = SVAL(inbuf,smb_vwv1) & 3;
3041 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
3042 startpos = (SMB_OFF_T)IVALS(inbuf,smb_vwv2);
3044 switch (mode) {
3045 case 0: umode = SEEK_SET; break;
3046 case 1: umode = SEEK_CUR; break;
3047 case 2: umode = SEEK_END; break;
3048 default:
3049 umode = SEEK_SET; break;
3052 if((res = conn->vfs_ops.lseek(fsp,fsp->fd,startpos,umode)) == -1) {
3054 * Check for the special case where a seek before the start
3055 * of the file sets the offset to zero. Added in the CIFS spec,
3056 * section 4.2.7.
3059 if(errno == EINVAL) {
3060 SMB_OFF_T current_pos = startpos;
3062 if(umode == SEEK_CUR) {
3064 if((current_pos = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) {
3065 END_PROFILE(SMBlseek);
3066 return(UNIXERROR(ERRDOS,ERRnoaccess));
3069 current_pos += startpos;
3071 } else if (umode == SEEK_END) {
3073 SMB_STRUCT_STAT sbuf;
3075 if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) {
3076 END_PROFILE(SMBlseek);
3077 return(UNIXERROR(ERRDOS,ERRnoaccess));
3080 current_pos += sbuf.st_size;
3083 if(current_pos < 0)
3084 res = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_SET);
3087 if(res == -1) {
3088 END_PROFILE(SMBlseek);
3089 return(UNIXERROR(ERRDOS,ERRnoaccess));
3093 fsp->pos = res;
3095 outsize = set_message(outbuf,2,0,True);
3096 SIVAL(outbuf,smb_vwv0,res);
3098 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
3099 fsp->fnum, (double)startpos, (double)res, mode));
3101 END_PROFILE(SMBlseek);
3102 return(outsize);
3105 /****************************************************************************
3106 Reply to a flush.
3107 ****************************************************************************/
3109 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
3111 int outsize = set_message(outbuf,0,0,True);
3112 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3113 START_PROFILE(SMBflush);
3115 CHECK_FSP(fsp,conn);
3117 if (!fsp) {
3118 file_sync_all(conn);
3119 } else {
3120 sync_file(conn,fsp);
3123 DEBUG(3,("flush\n"));
3124 END_PROFILE(SMBflush);
3125 return(outsize);
3128 /****************************************************************************
3129 Reply to a exit.
3130 ****************************************************************************/
3132 int reply_exit(connection_struct *conn,
3133 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3135 int outsize;
3136 START_PROFILE(SMBexit);
3137 outsize = set_message(outbuf,0,0,True);
3139 DEBUG(3,("exit\n"));
3141 END_PROFILE(SMBexit);
3142 return(outsize);
3146 /****************************************************************************
3147 Reply to a close - has to deal with closing a directory opened by NT SMB's.
3148 ****************************************************************************/
3150 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
3151 int dum_buffsize)
3153 extern struct current_user current_user;
3154 int outsize = 0;
3155 time_t mtime;
3156 files_struct *fsp = NULL;
3157 START_PROFILE(SMBclose);
3159 outsize = set_message(outbuf,0,0,True);
3161 /* If it's an IPC, pass off to the pipe handler. */
3162 if (IS_IPC(conn)) {
3163 END_PROFILE(SMBclose);
3164 return reply_pipe_close(conn, inbuf,outbuf);
3167 fsp = file_fsp(inbuf,smb_vwv0);
3170 * We can only use CHECK_FSP if we know it's not a directory.
3173 if(!fsp || (fsp->conn != conn) || (fsp->vuid != current_user.vuid)) {
3174 END_PROFILE(SMBclose);
3175 return ERROR_DOS(ERRDOS,ERRbadfid);
3178 if(fsp->is_directory) {
3180 * Special case - close NT SMB directory handle.
3182 DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
3183 close_file(fsp,True);
3184 } else {
3186 * Close ordinary file.
3188 int close_err;
3189 pstring file_name;
3191 /* Save the name for time set in close. */
3192 pstrcpy( file_name, fsp->fsp_name);
3194 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
3195 fsp->fd, fsp->fnum,
3196 conn->num_files_open));
3199 * close_file() returns the unix errno if an error
3200 * was detected on close - normally this is due to
3201 * a disk full error. If not then it was probably an I/O error.
3204 if((close_err = close_file(fsp,True)) != 0) {
3205 errno = close_err;
3206 END_PROFILE(SMBclose);
3207 return (UNIXERROR(ERRHRD,ERRgeneral));
3211 * Now take care of any time sent in the close.
3214 mtime = make_unix_date3(inbuf+smb_vwv1);
3216 /* try and set the date */
3217 set_filetime(conn, file_name, mtime);
3221 END_PROFILE(SMBclose);
3222 return(outsize);
3225 /****************************************************************************
3226 Reply to a writeclose (Core+ protocol)
3227 ****************************************************************************/
3229 int reply_writeclose(connection_struct *conn,
3230 char *inbuf,char *outbuf, int size, int dum_buffsize)
3232 size_t numtowrite;
3233 ssize_t nwritten = -1;
3234 int outsize = 0;
3235 int close_err = 0;
3236 SMB_OFF_T startpos;
3237 char *data;
3238 time_t mtime;
3239 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3240 START_PROFILE(SMBwriteclose);
3242 CHECK_FSP(fsp,conn);
3243 CHECK_WRITE(fsp);
3245 numtowrite = SVAL(inbuf,smb_vwv1);
3246 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
3247 mtime = make_unix_date3(inbuf+smb_vwv4);
3248 data = smb_buf(inbuf) + 1;
3250 if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
3251 END_PROFILE(SMBwriteclose);
3252 return ERROR_DOS(ERRDOS,ERRlock);
3255 nwritten = write_file(fsp,data,startpos,numtowrite);
3257 set_filetime(conn, fsp->fsp_name,mtime);
3259 close_err = close_file(fsp,True);
3261 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
3262 fsp->fnum, (int)numtowrite, (int)nwritten,
3263 conn->num_files_open));
3265 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
3266 END_PROFILE(SMBwriteclose);
3267 return(UNIXERROR(ERRHRD,ERRdiskfull));
3270 if(close_err != 0) {
3271 errno = close_err;
3272 END_PROFILE(SMBwriteclose);
3273 return(UNIXERROR(ERRHRD,ERRgeneral));
3276 outsize = set_message(outbuf,1,0,True);
3278 SSVAL(outbuf,smb_vwv0,nwritten);
3279 END_PROFILE(SMBwriteclose);
3280 return(outsize);
3283 /****************************************************************************
3284 Reply to a lock.
3285 ****************************************************************************/
3287 int reply_lock(connection_struct *conn,
3288 char *inbuf,char *outbuf, int length, int dum_buffsize)
3290 int outsize = set_message(outbuf,0,0,True);
3291 SMB_BIG_UINT count,offset;
3292 NTSTATUS status;
3293 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3294 START_PROFILE(SMBlock);
3296 CHECK_FSP(fsp,conn);
3298 release_level_2_oplocks_on_change(fsp);
3300 count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
3301 offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
3303 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
3304 fsp->fd, fsp->fnum, (double)offset, (double)count));
3306 status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
3307 if (NT_STATUS_V(status)) {
3308 if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
3310 * A blocking lock was requested. Package up
3311 * this smb into a queued request and push it
3312 * onto the blocking lock queue.
3314 if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), offset, count)) {
3315 END_PROFILE(SMBlock);
3316 return -1;
3319 END_PROFILE(SMBlock);
3320 return ERROR_NT(status);
3323 END_PROFILE(SMBlock);
3324 return(outsize);
3327 /****************************************************************************
3328 Reply to a unlock.
3329 ****************************************************************************/
3331 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
3333 int outsize = set_message(outbuf,0,0,True);
3334 SMB_BIG_UINT count,offset;
3335 NTSTATUS status;
3336 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3337 START_PROFILE(SMBunlock);
3339 CHECK_FSP(fsp,conn);
3341 count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
3342 offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
3344 status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
3345 if (NT_STATUS_V(status)) {
3346 END_PROFILE(SMBunlock);
3347 return ERROR_NT(status);
3350 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
3351 fsp->fd, fsp->fnum, (double)offset, (double)count ) );
3353 END_PROFILE(SMBunlock);
3354 return(outsize);
3357 /****************************************************************************
3358 Reply to a tdis.
3359 ****************************************************************************/
3361 int reply_tdis(connection_struct *conn,
3362 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3364 int outsize = set_message(outbuf,0,0,True);
3365 uint16 vuid;
3366 START_PROFILE(SMBtdis);
3368 vuid = SVAL(inbuf,smb_uid);
3370 if (!conn) {
3371 DEBUG(4,("Invalid connection in tdis\n"));
3372 END_PROFILE(SMBtdis);
3373 return ERROR_DOS(ERRSRV,ERRinvnid);
3376 conn->used = False;
3378 close_cnum(conn,vuid);
3380 END_PROFILE(SMBtdis);
3381 return outsize;
3384 /****************************************************************************
3385 Reply to a echo.
3386 ****************************************************************************/
3388 int reply_echo(connection_struct *conn,
3389 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3391 int smb_reverb = SVAL(inbuf,smb_vwv0);
3392 int seq_num;
3393 unsigned int data_len = smb_buflen(inbuf);
3394 int outsize = set_message(outbuf,1,data_len,True);
3395 START_PROFILE(SMBecho);
3397 data_len = MIN(data_len, (sizeof(inbuf)-(smb_buf(inbuf)-inbuf)));
3399 /* copy any incoming data back out */
3400 if (data_len > 0)
3401 memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
3403 if (smb_reverb > 100) {
3404 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
3405 smb_reverb = 100;
3408 for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
3409 SSVAL(outbuf,smb_vwv0,seq_num);
3411 smb_setlen(outbuf,outsize - 4);
3413 if (!send_smb(smbd_server_fd(),outbuf))
3414 exit_server("reply_echo: send_smb failed.");
3417 DEBUG(3,("echo %d times\n", smb_reverb));
3419 smb_echo_count++;
3421 END_PROFILE(SMBecho);
3422 return -1;
3425 /****************************************************************************
3426 Reply to a printopen.
3427 ****************************************************************************/
3429 int reply_printopen(connection_struct *conn,
3430 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3432 int outsize = 0;
3433 files_struct *fsp;
3434 START_PROFILE(SMBsplopen);
3436 if (!CAN_PRINT(conn)) {
3437 END_PROFILE(SMBsplopen);
3438 return ERROR_DOS(ERRDOS,ERRnoaccess);
3441 /* Open for exclusive use, write only. */
3442 fsp = print_fsp_open(conn, NULL);
3444 if (!fsp) {
3445 END_PROFILE(SMBsplopen);
3446 return(UNIXERROR(ERRDOS,ERRnoaccess));
3449 outsize = set_message(outbuf,1,0,True);
3450 SSVAL(outbuf,smb_vwv0,fsp->fnum);
3452 DEBUG(3,("openprint fd=%d fnum=%d\n",
3453 fsp->fd, fsp->fnum));
3455 END_PROFILE(SMBsplopen);
3456 return(outsize);
3459 /****************************************************************************
3460 Reply to a printclose.
3461 ****************************************************************************/
3463 int reply_printclose(connection_struct *conn,
3464 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3466 int outsize = set_message(outbuf,0,0,True);
3467 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3468 int close_err = 0;
3469 START_PROFILE(SMBsplclose);
3471 CHECK_FSP(fsp,conn);
3473 if (!CAN_PRINT(conn)) {
3474 END_PROFILE(SMBsplclose);
3475 return ERROR_DOS(ERRDOS,ERRnoaccess);
3478 DEBUG(3,("printclose fd=%d fnum=%d\n",
3479 fsp->fd,fsp->fnum));
3481 close_err = close_file(fsp,True);
3483 if(close_err != 0) {
3484 errno = close_err;
3485 END_PROFILE(SMBsplclose);
3486 return(UNIXERROR(ERRHRD,ERRgeneral));
3489 END_PROFILE(SMBsplclose);
3490 return(outsize);
3493 /****************************************************************************
3494 Reply to a printqueue.
3495 ****************************************************************************/
3497 int reply_printqueue(connection_struct *conn,
3498 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3500 int outsize = set_message(outbuf,2,3,True);
3501 int max_count = SVAL(inbuf,smb_vwv0);
3502 int start_index = SVAL(inbuf,smb_vwv1);
3503 START_PROFILE(SMBsplretq);
3505 /* we used to allow the client to get the cnum wrong, but that
3506 is really quite gross and only worked when there was only
3507 one printer - I think we should now only accept it if they
3508 get it right (tridge) */
3509 if (!CAN_PRINT(conn)) {
3510 END_PROFILE(SMBsplretq);
3511 return ERROR_DOS(ERRDOS,ERRnoaccess);
3514 SSVAL(outbuf,smb_vwv0,0);
3515 SSVAL(outbuf,smb_vwv1,0);
3516 SCVAL(smb_buf(outbuf),0,1);
3517 SSVAL(smb_buf(outbuf),1,0);
3519 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
3520 start_index, max_count));
3523 print_queue_struct *queue = NULL;
3524 print_status_struct status;
3525 char *p = smb_buf(outbuf) + 3;
3526 int count = print_queue_status(SNUM(conn), &queue, &status);
3527 int num_to_get = ABS(max_count);
3528 int first = (max_count>0?start_index:start_index+max_count+1);
3529 int i;
3531 if (first >= count)
3532 num_to_get = 0;
3533 else
3534 num_to_get = MIN(num_to_get,count-first);
3537 for (i=first;i<first+num_to_get;i++) {
3538 /* check to make sure we have room in the buffer */
3539 if ( (PTR_DIFF(p, outbuf)+28) > BUFFER_SIZE )
3540 break;
3541 put_dos_date2(p,0,queue[i].time);
3542 SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
3543 SSVAL(p,5, queue[i].job);
3544 SIVAL(p,7,queue[i].size);
3545 SCVAL(p,11,0);
3546 StrnCpy(p+12,queue[i].fs_user,16);
3547 p += 28;
3550 if (count > 0) {
3551 outsize = set_message(outbuf,2,28*count+3,False);
3552 SSVAL(outbuf,smb_vwv0,count);
3553 SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
3554 SCVAL(smb_buf(outbuf),0,1);
3555 SSVAL(smb_buf(outbuf),1,28*count);
3558 SAFE_FREE(queue);
3560 DEBUG(3,("%d entries returned in queue\n",count));
3563 END_PROFILE(SMBsplretq);
3564 return(outsize);
3567 /****************************************************************************
3568 Reply to a printwrite.
3569 ****************************************************************************/
3571 int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3573 int numtowrite;
3574 int outsize = set_message(outbuf,0,0,True);
3575 char *data;
3576 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3577 START_PROFILE(SMBsplwr);
3579 if (!CAN_PRINT(conn)) {
3580 END_PROFILE(SMBsplwr);
3581 return ERROR_DOS(ERRDOS,ERRnoaccess);
3584 CHECK_FSP(fsp,conn);
3585 CHECK_WRITE(fsp);
3587 numtowrite = SVAL(smb_buf(inbuf),1);
3588 data = smb_buf(inbuf) + 3;
3590 if (write_file(fsp,data,-1,numtowrite) != numtowrite) {
3591 END_PROFILE(SMBsplwr);
3592 return(UNIXERROR(ERRHRD,ERRdiskfull));
3595 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
3597 END_PROFILE(SMBsplwr);
3598 return(outsize);
3601 /****************************************************************************
3602 The guts of the mkdir command, split out so it may be called by the NT SMB
3603 code.
3604 ****************************************************************************/
3606 NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
3608 BOOL bad_path = False;
3609 SMB_STRUCT_STAT sbuf;
3610 int ret= -1;
3612 unix_convert(directory,conn,0,&bad_path,&sbuf);
3614 if (check_name(directory, conn))
3615 ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
3617 if (ret == -1) {
3618 NTSTATUS nterr = set_bad_path_error(errno, bad_path);
3619 if (!NT_STATUS_IS_OK(nterr))
3620 return nterr;
3621 return map_nt_error_from_unix(errno);
3624 return NT_STATUS_OK;
3627 /****************************************************************************
3628 Reply to a mkdir.
3629 ****************************************************************************/
3631 int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3633 pstring directory;
3634 int outsize;
3635 NTSTATUS status;
3636 START_PROFILE(SMBmkdir);
3638 pstrcpy(directory,smb_buf(inbuf) + 1);
3640 RESOLVE_DFSPATH(directory, conn, inbuf, outbuf);
3642 status = mkdir_internal(conn, directory);
3643 if (!NT_STATUS_IS_OK(status))
3644 return ERROR_NT(status);
3646 outsize = set_message(outbuf,0,0,True);
3648 DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
3650 END_PROFILE(SMBmkdir);
3651 return(outsize);
3654 /****************************************************************************
3655 Static function used by reply_rmdir to delete an entire directory
3656 tree recursively. Return False on ok, True on fail.
3657 ****************************************************************************/
3659 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
3661 char *dname = NULL;
3662 BOOL ret = False;
3663 void *dirptr = OpenDir(conn, directory, False);
3665 if(dirptr == NULL)
3666 return True;
3668 while((dname = ReadDirName(dirptr))) {
3669 pstring fullname;
3670 SMB_STRUCT_STAT st;
3672 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3673 continue;
3675 /* Construct the full name. */
3676 if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
3677 errno = ENOMEM;
3678 ret = True;
3679 break;
3682 pstrcpy(fullname, directory);
3683 pstrcat(fullname, "/");
3684 pstrcat(fullname, dname);
3686 if(conn->vfs_ops.lstat(conn,dos_to_unix_static(fullname), &st) != 0) {
3687 ret = True;
3688 break;
3691 if(st.st_mode & S_IFDIR) {
3692 if(recursive_rmdir(conn, fullname)!=0) {
3693 ret = True;
3694 break;
3696 if(vfs_rmdir(conn,fullname) != 0) {
3697 ret = True;
3698 break;
3700 } else if(vfs_unlink(conn,fullname) != 0) {
3701 ret = True;
3702 break;
3706 CloseDir(dirptr);
3707 return ret;
3710 /****************************************************************************
3711 The internals of the rmdir code - called elsewhere.
3712 ****************************************************************************/
3714 BOOL rmdir_internals(connection_struct *conn, char *directory)
3716 BOOL ok;
3718 ok = (vfs_rmdir(conn,directory) == 0);
3719 if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
3721 * Check to see if the only thing in this directory are
3722 * vetoed files/directories. If so then delete them and
3723 * retry. If we fail to delete any of them (and we *don't*
3724 * do a recursive delete) then fail the rmdir.
3726 BOOL all_veto_files = True;
3727 char *dname;
3728 void *dirptr = OpenDir(conn, directory, False);
3730 if(dirptr != NULL) {
3731 int dirpos = TellDir(dirptr);
3732 while ((dname = ReadDirName(dirptr))) {
3733 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3734 continue;
3735 if(!IS_VETO_PATH(conn, dname)) {
3736 all_veto_files = False;
3737 break;
3740 if(all_veto_files) {
3741 SeekDir(dirptr,dirpos);
3742 while ((dname = ReadDirName(dirptr))) {
3743 pstring fullname;
3744 SMB_STRUCT_STAT st;
3746 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3747 continue;
3749 /* Construct the full name. */
3750 if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
3751 errno = ENOMEM;
3752 break;
3754 pstrcpy(fullname, directory);
3755 pstrcat(fullname, "/");
3756 pstrcat(fullname, dname);
3758 if(conn->vfs_ops.lstat(conn,dos_to_unix_static(fullname), &st) != 0)
3759 break;
3760 if(st.st_mode & S_IFDIR) {
3761 if(lp_recursive_veto_delete(SNUM(conn))) {
3762 if(recursive_rmdir(conn, fullname) != 0)
3763 break;
3765 if(vfs_rmdir(conn,fullname) != 0)
3766 break;
3767 } else if(vfs_unlink(conn,fullname) != 0)
3768 break;
3770 CloseDir(dirptr);
3771 /* Retry the rmdir */
3772 ok = (vfs_rmdir(conn,directory) == 0);
3773 } else {
3774 CloseDir(dirptr);
3776 } else {
3777 errno = ENOTEMPTY;
3781 if (!ok)
3782 DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno)));
3784 return ok;
3787 /****************************************************************************
3788 Reply to a rmdir.
3789 ****************************************************************************/
3791 int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3793 pstring directory;
3794 int outsize = 0;
3795 BOOL ok = False;
3796 BOOL bad_path = False;
3797 SMB_STRUCT_STAT sbuf;
3798 START_PROFILE(SMBrmdir);
3800 pstrcpy(directory,smb_buf(inbuf) + 1);
3802 RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
3804 unix_convert(directory,conn, NULL,&bad_path,&sbuf);
3806 if (check_name(directory,conn))
3808 dptr_closepath(directory,SVAL(inbuf,smb_pid));
3809 ok = rmdir_internals(conn, directory);
3812 if (!ok)
3814 set_bad_path_error(errno, bad_path);
3815 END_PROFILE(SMBrmdir);
3816 return(UNIXERROR(ERRDOS,ERRbadpath));
3819 outsize = set_message(outbuf,0,0,True);
3821 DEBUG( 3, ( "rmdir %s\n", directory ) );
3823 END_PROFILE(SMBrmdir);
3824 return(outsize);
3827 /*******************************************************************
3828 Resolve wildcards in a filename rename.
3829 ********************************************************************/
3831 static BOOL resolve_wildcards(char *name1,char *name2)
3833 fstring root1,root2;
3834 fstring ext1,ext2;
3835 char *p,*p2;
3837 name1 = strrchr(name1,'/');
3838 name2 = strrchr(name2,'/');
3840 if (!name1 || !name2) return(False);
3842 fstrcpy(root1,name1);
3843 fstrcpy(root2,name2);
3844 p = strrchr(root1,'.');
3845 if (p) {
3846 *p = 0;
3847 fstrcpy(ext1,p+1);
3848 } else {
3849 fstrcpy(ext1,"");
3851 p = strrchr(root2,'.');
3852 if (p) {
3853 *p = 0;
3854 fstrcpy(ext2,p+1);
3855 } else {
3856 fstrcpy(ext2,"");
3859 p = root1;
3860 p2 = root2;
3861 while (*p2) {
3862 if (*p2 == '?') {
3863 *p2 = *p;
3864 p2++;
3865 } else {
3866 p2++;
3868 if (*p) p++;
3871 p = ext1;
3872 p2 = ext2;
3873 while (*p2) {
3874 if (*p2 == '?') {
3875 *p2 = *p;
3876 p2++;
3877 } else {
3878 p2++;
3880 if (*p) p++;
3883 pstrcpy(name2,root2);
3884 if (ext2[0]) {
3885 pstrcat(name2,".");
3886 pstrcat(name2,ext2);
3889 return(True);
3892 /****************************************************************************
3893 The guts of the rename command, split out so it may be called by the NT SMB
3894 code.
3895 ****************************************************************************/
3897 NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BOOL replace_if_exists)
3899 pstring directory;
3900 pstring mask;
3901 pstring newname_last_component;
3902 char *p;
3903 BOOL has_wild;
3904 BOOL bad_path1 = False;
3905 BOOL bad_path2 = False;
3906 int count=0;
3907 NTSTATUS error = NT_STATUS_OK;
3908 BOOL rc = True;
3909 SMB_STRUCT_STAT sbuf1, sbuf2;
3911 *directory = *mask = 0;
3913 rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
3914 unix_convert(newname,conn,newname_last_component,&bad_path2,&sbuf2);
3917 * Split the old name into directory and last component
3918 * strings. Note that unix_convert may have stripped off a
3919 * leading ./ from both name and newname if the rename is
3920 * at the root of the share. We need to make sure either both
3921 * name and newname contain a / character or neither of them do
3922 * as this is checked in resolve_wildcards().
3925 p = strrchr(name,'/');
3926 if (!p) {
3927 pstrcpy(directory,".");
3928 pstrcpy(mask,name);
3929 } else {
3930 *p = 0;
3931 pstrcpy(directory,name);
3932 pstrcpy(mask,p+1);
3933 *p = '/'; /* Replace needed for exceptional test below. */
3937 * We should only check the mangled cache
3938 * here if unix_convert failed. This means
3939 * that the path in 'mask' doesn't exist
3940 * on the file system and so we need to look
3941 * for a possible mangle. This patch from
3942 * Tine Smukavec <valentin.smukavec@hermes.si>.
3945 if (!rc && mangle_is_mangled(mask))
3946 mangle_check_cache( mask );
3948 has_wild = ms_has_wild(mask);
3950 if (!has_wild) {
3951 pstring zdirectory;
3952 pstring znewname;
3955 * No wildcards - just process the one file.
3957 BOOL is_short_name = mangle_is_8_3(name, True);
3959 /* Add a terminating '/' to the directory name. */
3960 pstrcat(directory,"/");
3961 pstrcat(directory,mask);
3963 /* Ensure newname contains a '/' also */
3964 if(strrchr(newname,'/') == 0) {
3965 pstring tmpstr;
3967 pstrcpy(tmpstr, "./");
3968 pstrcat(tmpstr, newname);
3969 pstrcpy(newname, tmpstr);
3972 DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
3973 directory = %s, newname = %s, newname_last_component = %s, mangle_is_8_3 = %d\n",
3974 case_sensitive, case_preserve, short_case_preserve, directory,
3975 newname, newname_last_component, is_short_name));
3978 * Check for special case with case preserving and not
3979 * case sensitive, if directory and newname are identical,
3980 * and the old last component differs from the original
3981 * last component only by case, then we should allow
3982 * the rename (user is trying to change the case of the
3983 * filename).
3985 if((case_sensitive == False) &&
3986 (((case_preserve == True) &&
3987 (is_short_name == False)) ||
3988 ((short_case_preserve == True) &&
3989 (is_short_name == True))) &&
3990 strcsequal(directory, newname)) {
3991 pstring newname_modified_last_component;
3994 * Get the last component of the modified name.
3995 * Note that we guarantee that newname contains a '/'
3996 * character above.
3998 p = strrchr(newname,'/');
3999 pstrcpy(newname_modified_last_component,p+1);
4001 if(strcsequal(newname_modified_last_component,
4002 newname_last_component) == False) {
4004 * Replace the modified last component with
4005 * the original.
4007 pstrcpy(p+1, newname_last_component);
4012 resolve_wildcards(directory,newname);
4015 * The source object must exist.
4018 if (!vfs_object_exist(conn, directory, &sbuf1)) {
4019 DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",
4020 directory,newname));
4022 if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) {
4024 * Must return different errors depending on whether the parent
4025 * directory existed or not.
4028 p = strrchr(directory, '/');
4029 if (!p)
4030 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4031 *p = '\0';
4032 if (vfs_object_exist(conn, directory, NULL))
4033 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4034 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
4036 error = map_nt_error_from_unix(errno);
4037 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
4038 get_nt_error_msg(error), directory,newname));
4040 return error;
4043 error = can_rename(directory,conn,&sbuf1);
4045 if (!NT_STATUS_IS_OK(error)) {
4046 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
4047 get_nt_error_msg(error), directory,newname));
4048 return error;
4051 pstrcpy(zdirectory, dos_to_unix_static(directory));
4052 pstrcpy(znewname, dos_to_unix_static(newname));
4055 * If the src and dest names are identical - including case,
4056 * don't do the rename, just return success.
4059 if (strcsequal(zdirectory, znewname)) {
4060 DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
4061 return NT_STATUS_OK;
4064 if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
4065 DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n",
4066 directory,newname));
4067 return NT_STATUS_OBJECT_NAME_COLLISION;
4070 if(conn->vfs_ops.rename(conn,zdirectory, znewname) == 0) {
4071 DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
4072 directory,newname));
4073 return NT_STATUS_OK;
4076 if (errno == ENOTDIR || errno == EISDIR)
4077 error = NT_STATUS_OBJECT_NAME_COLLISION;
4078 else
4079 error = map_nt_error_from_unix(errno);
4081 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
4082 get_nt_error_msg(error), directory,newname));
4084 return error;
4085 } else {
4088 * Wildcards - process each file that matches.
4090 void *dirptr = NULL;
4091 char *dname;
4092 pstring destname;
4094 if (check_name(directory,conn))
4095 dirptr = OpenDir(conn, directory, True);
4097 if (dirptr) {
4098 error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
4100 if (strequal(mask,"????????.???"))
4101 pstrcpy(mask,"*");
4103 while ((dname = ReadDirName(dirptr))) {
4104 pstring fname;
4106 pstrcpy(fname,dname);
4108 if(!mask_match(fname, mask, case_sensitive))
4109 continue;
4111 error = NT_STATUS_ACCESS_DENIED;
4112 slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
4113 if (!vfs_object_exist(conn, fname, &sbuf1)) {
4114 error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
4115 DEBUG(6,("rename %s failed. Error %s\n", fname, get_nt_error_msg(error)));
4116 continue;
4118 error = can_rename(fname,conn,&sbuf1);
4119 if (!NT_STATUS_IS_OK(error)) {
4120 DEBUG(6,("rename %s failed. Error %s\n", fname, get_nt_error_msg(error)));
4121 continue;
4123 pstrcpy(destname,newname);
4125 if (!resolve_wildcards(fname,destname)) {
4126 DEBUG(6,("resolve_wildcards %s %s failed\n",
4127 fname, destname));
4128 continue;
4131 if (!replace_if_exists &&
4132 vfs_object_exist(conn,destname, NULL)) {
4133 DEBUG(6,("file_exist %s\n", destname));
4134 error = NT_STATUS_OBJECT_NAME_COLLISION;
4135 continue;
4138 if (!conn->vfs_ops.rename(conn,dos_to_unix_static(fname),
4139 dos_to_unix_static(destname)))
4140 count++;
4141 DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
4143 CloseDir(dirptr);
4147 if (count == 0 && NT_STATUS_IS_OK(error)) {
4148 error = map_nt_error_from_unix(errno);
4151 return error;
4154 /****************************************************************************
4155 Reply to a mv.
4156 ****************************************************************************/
4158 int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4160 int outsize = 0;
4161 pstring name;
4162 pstring newname;
4163 NTSTATUS status;
4164 START_PROFILE(SMBmv);
4166 pstrcpy(name,smb_buf(inbuf) + 1);
4167 pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
4169 RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
4170 RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
4172 DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
4174 status = rename_internals(conn, name, newname, False);
4175 if (!NT_STATUS_IS_OK(status)) {
4176 return ERROR_NT(status);
4180 * Win2k needs a changenotify request response before it will
4181 * update after a rename..
4183 process_pending_change_notify_queue((time_t)0);
4184 outsize = set_message(outbuf,0,0,True);
4186 END_PROFILE(SMBmv);
4187 return(outsize);
4190 /*******************************************************************
4191 Copy a file as part of a reply_copy.
4192 ******************************************************************/
4194 static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
4195 int count,BOOL target_is_directory, int *err_ret)
4197 int Access,action;
4198 SMB_STRUCT_STAT src_sbuf, sbuf2;
4199 SMB_OFF_T ret=-1;
4200 files_struct *fsp1,*fsp2;
4201 pstring dest;
4203 *err_ret = 0;
4205 pstrcpy(dest,dest1);
4206 if (target_is_directory) {
4207 char *p = strrchr(src,'/');
4208 if (p)
4209 p++;
4210 else
4211 p = src;
4212 pstrcat(dest,"/");
4213 pstrcat(dest,p);
4216 if (!vfs_file_exist(conn,src,&src_sbuf))
4217 return(False);
4219 fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
4220 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
4222 if (!fsp1)
4223 return(False);
4225 if (!target_is_directory && count)
4226 ofun = FILE_EXISTS_OPEN;
4228 if (vfs_stat(conn,dest,&sbuf2) == -1)
4229 ZERO_STRUCTP(&sbuf2);
4231 fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
4232 ofun,src_sbuf.st_mode,0,&Access,&action);
4234 if (!fsp2) {
4235 close_file(fsp1,False);
4236 return(False);
4239 if ((ofun&3) == 1) {
4240 if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) {
4241 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
4243 * Stop the copy from occurring.
4245 ret = -1;
4246 src_sbuf.st_size = 0;
4250 if (src_sbuf.st_size)
4251 ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
4253 close_file(fsp1,False);
4255 /* Ensure the modtime is set correctly on the destination file. */
4256 fsp2->pending_modtime = src_sbuf.st_mtime;
4259 * As we are opening fsp1 read-only we only expect
4260 * an error on close on fsp2 if we are out of space.
4261 * Thus we don't look at the error return from the
4262 * close of fsp1.
4264 *err_ret = close_file(fsp2,False);
4266 return(ret == (SMB_OFF_T)src_sbuf.st_size);
4269 /****************************************************************************
4270 Reply to a file copy.
4271 ****************************************************************************/
4273 int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4275 int outsize = 0;
4276 pstring name;
4277 pstring directory;
4278 pstring mask,newname;
4279 char *p;
4280 int count=0;
4281 int error = ERRnoaccess;
4282 int err = 0;
4283 BOOL has_wild;
4284 BOOL exists=False;
4285 int tid2 = SVAL(inbuf,smb_vwv0);
4286 int ofun = SVAL(inbuf,smb_vwv1);
4287 int flags = SVAL(inbuf,smb_vwv2);
4288 BOOL target_is_directory=False;
4289 BOOL bad_path1 = False;
4290 BOOL bad_path2 = False;
4291 BOOL rc = True;
4292 SMB_STRUCT_STAT sbuf1, sbuf2;
4293 START_PROFILE(SMBcopy);
4295 *directory = *mask = 0;
4297 pstrcpy(name,smb_buf(inbuf));
4298 pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
4300 DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
4302 if (tid2 != conn->cnum) {
4303 /* can't currently handle inter share copies XXXX */
4304 DEBUG(3,("Rejecting inter-share copy\n"));
4305 END_PROFILE(SMBcopy);
4306 return ERROR_DOS(ERRSRV,ERRinvdevice);
4309 RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
4310 RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
4312 rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
4313 unix_convert(newname,conn,0,&bad_path2,&sbuf2);
4315 target_is_directory = VALID_STAT_OF_DIR(sbuf2);
4317 if ((flags&1) && target_is_directory) {
4318 END_PROFILE(SMBcopy);
4319 return ERROR_DOS(ERRDOS,ERRbadfile);
4322 if ((flags&2) && !target_is_directory) {
4323 END_PROFILE(SMBcopy);
4324 return ERROR_DOS(ERRDOS,ERRbadpath);
4327 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
4328 /* wants a tree copy! XXXX */
4329 DEBUG(3,("Rejecting tree copy\n"));
4330 END_PROFILE(SMBcopy);
4331 return ERROR_DOS(ERRSRV,ERRerror);
4334 p = strrchr(name,'/');
4335 if (!p) {
4336 pstrcpy(directory,"./");
4337 pstrcpy(mask,name);
4338 } else {
4339 *p = 0;
4340 pstrcpy(directory,name);
4341 pstrcpy(mask,p+1);
4345 * We should only check the mangled cache
4346 * here if unix_convert failed. This means
4347 * that the path in 'mask' doesn't exist
4348 * on the file system and so we need to look
4349 * for a possible mangle. This patch from
4350 * Tine Smukavec <valentin.smukavec@hermes.si>.
4353 if (!rc && mangle_is_mangled(mask))
4354 mangle_check_cache( mask );
4356 has_wild = ms_has_wild(mask);
4358 if (!has_wild) {
4359 pstrcat(directory,"/");
4360 pstrcat(directory,mask);
4361 if (resolve_wildcards(directory,newname) &&
4362 copy_file(directory,newname,conn,ofun,
4363 count,target_is_directory,&err)) count++;
4364 if(!count && err) {
4365 errno = err;
4366 END_PROFILE(SMBcopy);
4367 return(UNIXERROR(ERRHRD,ERRgeneral));
4369 if (!count) exists = vfs_file_exist(conn,directory,NULL);
4370 } else {
4371 void *dirptr = NULL;
4372 char *dname;
4373 pstring destname;
4375 if (check_name(directory,conn))
4376 dirptr = OpenDir(conn, directory, True);
4378 if (dirptr) {
4379 error = ERRbadfile;
4381 if (strequal(mask,"????????.???"))
4382 pstrcpy(mask,"*");
4384 while ((dname = ReadDirName(dirptr))) {
4385 pstring fname;
4386 pstrcpy(fname,dname);
4388 if(!mask_match(fname, mask, case_sensitive))
4389 continue;
4391 error = ERRnoaccess;
4392 slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
4393 pstrcpy(destname,newname);
4394 if (resolve_wildcards(fname,destname) &&
4395 copy_file(fname,destname,conn,ofun,
4396 count,target_is_directory,&err)) count++;
4397 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
4399 CloseDir(dirptr);
4403 if (count == 0) {
4404 if(err) {
4405 /* Error on close... */
4406 errno = err;
4407 END_PROFILE(SMBcopy);
4408 return(UNIXERROR(ERRHRD,ERRgeneral));
4411 if (exists) {
4412 END_PROFILE(SMBcopy);
4413 return ERROR_DOS(ERRDOS,error);
4414 } else
4416 if((errno == ENOENT) && (bad_path1 || bad_path2))
4418 unix_ERR_class = ERRDOS;
4419 unix_ERR_code = ERRbadpath;
4421 END_PROFILE(SMBcopy);
4422 return(UNIXERROR(ERRDOS,error));
4426 outsize = set_message(outbuf,1,0,True);
4427 SSVAL(outbuf,smb_vwv0,count);
4429 END_PROFILE(SMBcopy);
4430 return(outsize);
4433 /****************************************************************************
4434 Reply to a setdir.
4435 ****************************************************************************/
4437 int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4439 int snum;
4440 int outsize = 0;
4441 BOOL ok = False;
4442 pstring newdir;
4443 START_PROFILE(pathworks_setdir);
4445 snum = SNUM(conn);
4446 if (!CAN_SETDIR(snum)) {
4447 END_PROFILE(pathworks_setdir);
4448 return ERROR_DOS(ERRDOS,ERRnoaccess);
4451 pstrcpy(newdir,smb_buf(inbuf) + 1);
4452 strlower(newdir);
4454 if (strlen(newdir) == 0) {
4455 ok = True;
4456 } else {
4457 ok = vfs_directory_exist(conn,newdir,NULL);
4458 if (ok) {
4459 string_set(&conn->connectpath,newdir);
4463 if (!ok) {
4464 END_PROFILE(pathworks_setdir);
4465 return ERROR_DOS(ERRDOS,ERRbadpath);
4468 outsize = set_message(outbuf,0,0,True);
4469 SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
4471 DEBUG(3,("setdir %s\n", newdir));
4473 END_PROFILE(pathworks_setdir);
4474 return(outsize);
4477 /****************************************************************************
4478 Get a lock pid, dealing with large count requests.
4479 ****************************************************************************/
4481 uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
4483 if(!large_file_format)
4484 return SVAL(data,SMB_LPID_OFFSET(data_offset));
4485 else
4486 return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
4489 /****************************************************************************
4490 Get a lock count, dealing with large count requests.
4491 ****************************************************************************/
4493 SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format)
4495 SMB_BIG_UINT count = 0;
4497 if(!large_file_format) {
4498 count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
4499 } else {
4501 #if defined(HAVE_LONGLONG)
4502 count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
4503 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
4504 #else /* HAVE_LONGLONG */
4507 * NT4.x seems to be broken in that it sends large file (64 bit)
4508 * lockingX calls even if the CAP_LARGE_FILES was *not*
4509 * negotiated. For boxes without large unsigned ints truncate the
4510 * lock count by dropping the top 32 bits.
4513 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
4514 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
4515 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
4516 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
4517 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
4520 count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
4521 #endif /* HAVE_LONGLONG */
4524 return count;
4527 #if !defined(HAVE_LONGLONG)
4528 /****************************************************************************
4529 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
4530 ****************************************************************************/
4532 static uint32 map_lock_offset(uint32 high, uint32 low)
4534 unsigned int i;
4535 uint32 mask = 0;
4536 uint32 highcopy = high;
4539 * Try and find out how many significant bits there are in high.
4542 for(i = 0; highcopy; i++)
4543 highcopy >>= 1;
4546 * We use 31 bits not 32 here as POSIX
4547 * lock offsets may not be negative.
4550 mask = (~0) << (31 - i);
4552 if(low & mask)
4553 return 0; /* Fail. */
4555 high <<= (31 - i);
4557 return (high|low);
4559 #endif /* !defined(HAVE_LONGLONG) */
4561 /****************************************************************************
4562 Get a lock offset, dealing with large offset requests.
4563 ****************************************************************************/
4565 SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
4567 SMB_BIG_UINT offset = 0;
4569 *err = False;
4571 if(!large_file_format) {
4572 offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
4573 } else {
4575 #if defined(HAVE_LONGLONG)
4576 offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
4577 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
4578 #else /* HAVE_LONGLONG */
4581 * NT4.x seems to be broken in that it sends large file (64 bit)
4582 * lockingX calls even if the CAP_LARGE_FILES was *not*
4583 * negotiated. For boxes without large unsigned ints mangle the
4584 * lock offset by mapping the top 32 bits onto the lower 32.
4587 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
4588 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
4589 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
4590 uint32 new_low = 0;
4592 if((new_low = map_lock_offset(high, low)) == 0) {
4593 *err = True;
4594 return (SMB_BIG_UINT)-1;
4597 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
4598 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
4599 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
4600 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
4603 offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
4604 #endif /* HAVE_LONGLONG */
4607 return offset;
4610 /****************************************************************************
4611 Reply to a lockingX request.
4612 ****************************************************************************/
4614 int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
4616 files_struct *fsp = file_fsp(inbuf,smb_vwv2);
4617 unsigned char locktype = CVAL(inbuf,smb_vwv3);
4618 unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
4619 uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
4620 uint16 num_locks = SVAL(inbuf,smb_vwv7);
4621 SMB_BIG_UINT count = 0, offset = 0;
4622 uint16 lock_pid;
4623 int32 lock_timeout = IVAL(inbuf,smb_vwv4);
4624 int i;
4625 char *data;
4626 BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
4627 BOOL err;
4628 NTSTATUS status;
4630 START_PROFILE(SMBlockingX);
4632 CHECK_FSP(fsp,conn);
4634 data = smb_buf(inbuf);
4636 if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4637 /* we don't support these - and CANCEL_LOCK makes w2k
4638 and XP reboot so I don't really want to be
4639 compatible! (tridge) */
4640 return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
4643 /* Check if this is an oplock break on a file
4644 we have granted an oplock on.
4646 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
4647 /* Client can insist on breaking to none. */
4648 BOOL break_to_none = (oplocklevel == 0);
4650 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n",
4651 (unsigned int)oplocklevel, fsp->fnum ));
4654 * Make sure we have granted an exclusive or batch oplock on this file.
4657 if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
4658 DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
4659 no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
4661 /* if this is a pure oplock break request then don't send a reply */
4662 if (num_locks == 0 && num_ulocks == 0) {
4663 END_PROFILE(SMBlockingX);
4664 return -1;
4665 } else {
4666 END_PROFILE(SMBlockingX);
4667 return ERROR_DOS(ERRDOS,ERRlock);
4671 if (remove_oplock(fsp, break_to_none) == False) {
4672 DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
4673 fsp->fsp_name ));
4676 /* if this is a pure oplock break request then don't send a reply */
4677 if (num_locks == 0 && num_ulocks == 0) {
4678 /* Sanity check - ensure a pure oplock break is not a
4679 chained request. */
4680 if(CVAL(inbuf,smb_vwv0) != 0xff)
4681 DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
4682 (unsigned int)CVAL(inbuf,smb_vwv0) ));
4683 END_PROFILE(SMBlockingX);
4684 return -1;
4689 * We do this check *after* we have checked this is not a oplock break
4690 * response message. JRA.
4693 release_level_2_oplocks_on_change(fsp);
4695 /* Data now points at the beginning of the list
4696 of smb_unlkrng structs */
4697 for(i = 0; i < (int)num_ulocks; i++) {
4698 lock_pid = get_lock_pid( data, i, large_file_format);
4699 count = get_lock_count( data, i, large_file_format);
4700 offset = get_lock_offset( data, i, large_file_format, &err);
4703 * There is no error code marked "stupid client bug".... :-).
4705 if(err) {
4706 END_PROFILE(SMBlockingX);
4707 return ERROR_DOS(ERRDOS,ERRnoaccess);
4710 DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n",
4711 (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
4713 status = do_unlock(fsp,conn,lock_pid,count,offset);
4714 if (NT_STATUS_V(status)) {
4715 END_PROFILE(SMBlockingX);
4716 return ERROR_NT(status);
4720 /* Setup the timeout in seconds. */
4722 lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
4724 /* Now do any requested locks */
4725 data += ((large_file_format ? 20 : 10)*num_ulocks);
4727 /* Data now points at the beginning of the list
4728 of smb_lkrng structs */
4730 for(i = 0; i < (int)num_locks; i++) {
4731 lock_pid = get_lock_pid( data, i, large_file_format);
4732 count = get_lock_count( data, i, large_file_format);
4733 offset = get_lock_offset( data, i, large_file_format, &err);
4736 * There is no error code marked "stupid client bug".... :-).
4738 if(err) {
4739 END_PROFILE(SMBlockingX);
4740 return ERROR_DOS(ERRDOS,ERRnoaccess);
4743 DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d\n",
4744 (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name,
4745 (int)lock_timeout ));
4747 status = do_lock_spin(fsp,conn,lock_pid, count,offset,
4748 ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
4750 if (NT_STATUS_V(status)) {
4751 if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
4753 * A blocking lock was requested. Package up
4754 * this smb into a queued request and push it
4755 * onto the blocking lock queue.
4757 if(push_blocking_lock_request(inbuf, length, lock_timeout, i, lock_pid, offset, count)) {
4758 END_PROFILE(SMBlockingX);
4759 return -1;
4762 break;
4766 /* If any of the above locks failed, then we must unlock
4767 all of the previous locks (X/Open spec). */
4768 if(i != num_locks && num_locks != 0) {
4770 * Ensure we don't do a remove on the lock that just failed,
4771 * as under POSIX rules, if we have a lock already there, we
4772 * will delete it (and we shouldn't) .....
4774 for(i--; i >= 0; i--) {
4775 lock_pid = get_lock_pid( data, i, large_file_format);
4776 count = get_lock_count( data, i, large_file_format);
4777 offset = get_lock_offset( data, i, large_file_format, &err);
4780 * There is no error code marked "stupid client bug".... :-).
4782 if(err) {
4783 END_PROFILE(SMBlockingX);
4784 return ERROR_DOS(ERRDOS,ERRnoaccess);
4787 do_unlock(fsp,conn,lock_pid,count,offset);
4789 END_PROFILE(SMBlockingX);
4790 return ERROR_NT(status);
4793 set_message(outbuf,2,0,True);
4795 DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
4796 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
4798 END_PROFILE(SMBlockingX);
4799 return chain_reply(inbuf,outbuf,length,bufsize);
4802 /* Back from the dead for OS/2..... JRA. */
4804 /****************************************************************************
4805 Reply to a SMBreadbmpx (read block multiplex) request
4806 ****************************************************************************/
4808 int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
4810 ssize_t nread = -1;
4811 ssize_t total_read;
4812 char *data;
4813 SMB_OFF_T startpos;
4814 int outsize;
4815 size_t maxcount;
4816 int max_per_packet;
4817 size_t tcount;
4818 int pad;
4819 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4820 START_PROFILE(SMBreadBmpx);
4822 /* this function doesn't seem to work - disable by default */
4823 if (!lp_readbmpx()) {
4824 END_PROFILE(SMBreadBmpx);
4825 return ERROR_DOS(ERRSRV,ERRuseSTD);
4828 outsize = set_message(outbuf,8,0,True);
4830 CHECK_FSP(fsp,conn);
4831 CHECK_READ(fsp);
4832 CHECK_ERROR(fsp);
4834 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
4835 maxcount = SVAL(inbuf,smb_vwv3);
4837 data = smb_buf(outbuf);
4838 pad = ((long)data)%4;
4839 if (pad)
4840 pad = 4 - pad;
4841 data += pad;
4843 max_per_packet = bufsize-(outsize+pad);
4844 tcount = maxcount;
4845 total_read = 0;
4847 if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK, False)) {
4848 END_PROFILE(SMBreadBmpx);
4849 return ERROR_DOS(ERRDOS,ERRlock);
4852 do {
4853 size_t N = MIN(max_per_packet,tcount-total_read);
4855 nread = read_file(fsp,data,startpos,N);
4857 if (nread <= 0)
4858 nread = 0;
4860 if (nread < (ssize_t)N)
4861 tcount = total_read + nread;
4863 set_message(outbuf,8,nread,False);
4864 SIVAL(outbuf,smb_vwv0,startpos);
4865 SSVAL(outbuf,smb_vwv2,tcount);
4866 SSVAL(outbuf,smb_vwv6,nread);
4867 SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
4869 if (!send_smb(smbd_server_fd(),outbuf))
4870 exit_server("reply_readbmpx: send_smb failed.");
4872 total_read += nread;
4873 startpos += nread;
4874 } while (total_read < (ssize_t)tcount);
4876 END_PROFILE(SMBreadBmpx);
4877 return(-1);
4880 /****************************************************************************
4881 Reply to a SMBsetattrE.
4882 ****************************************************************************/
4884 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4886 struct utimbuf unix_times;
4887 int outsize = 0;
4888 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4889 START_PROFILE(SMBsetattrE);
4891 outsize = set_message(outbuf,0,0,True);
4893 if(!fsp || (fsp->conn != conn)) {
4894 END_PROFILE(SMBsetattrE);
4895 return ERROR_DOS(ERRDOS,ERRbadfid);
4899 * Convert the DOS times into unix times. Ignore create
4900 * time as UNIX can't set this.
4902 unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
4903 unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
4906 * Patch from Ray Frush <frush@engr.colostate.edu>
4907 * Sometimes times are sent as zero - ignore them.
4910 if ((unix_times.actime == 0) && (unix_times.modtime == 0)) {
4911 /* Ignore request */
4912 if( DEBUGLVL( 3 ) ) {
4913 dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
4914 dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
4916 END_PROFILE(SMBsetattrE);
4917 return(outsize);
4918 } else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) {
4919 /* set modify time = to access time if modify time was 0 */
4920 unix_times.modtime = unix_times.actime;
4923 /* Set the date on this file */
4924 if(file_utime(conn, fsp->fsp_name, &unix_times)) {
4925 END_PROFILE(SMBsetattrE);
4926 return ERROR_DOS(ERRDOS,ERRnoaccess);
4929 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
4930 fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
4932 END_PROFILE(SMBsetattrE);
4933 return(outsize);
4937 /* Back from the dead for OS/2..... JRA. */
4939 /****************************************************************************
4940 Reply to a SMBwritebmpx (write block multiplex primary) request.
4941 ****************************************************************************/
4943 int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4945 size_t numtowrite;
4946 ssize_t nwritten = -1;
4947 int outsize = 0;
4948 SMB_OFF_T startpos;
4949 size_t tcount;
4950 BOOL write_through;
4951 int smb_doff;
4952 char *data;
4953 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4954 START_PROFILE(SMBwriteBmpx);
4956 CHECK_FSP(fsp,conn);
4957 CHECK_WRITE(fsp);
4958 CHECK_ERROR(fsp);
4960 tcount = SVAL(inbuf,smb_vwv1);
4961 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
4962 write_through = BITSETW(inbuf+smb_vwv7,0);
4963 numtowrite = SVAL(inbuf,smb_vwv10);
4964 smb_doff = SVAL(inbuf,smb_vwv11);
4966 data = smb_base(inbuf) + smb_doff;
4968 /* If this fails we need to send an SMBwriteC response,
4969 not an SMBwritebmpx - set this up now so we don't forget */
4970 SCVAL(outbuf,smb_com,SMBwritec);
4972 if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) {
4973 END_PROFILE(SMBwriteBmpx);
4974 return(ERROR_DOS(ERRDOS,ERRlock));
4977 nwritten = write_file(fsp,data,startpos,numtowrite);
4979 if(lp_syncalways(SNUM(conn)) || write_through)
4980 sync_file(conn,fsp);
4982 if(nwritten < (ssize_t)numtowrite) {
4983 END_PROFILE(SMBwriteBmpx);
4984 return(UNIXERROR(ERRHRD,ERRdiskfull));
4987 /* If the maximum to be written to this file
4988 is greater than what we just wrote then set
4989 up a secondary struct to be attached to this
4990 fd, we will use this to cache error messages etc. */
4992 if((ssize_t)tcount > nwritten) {
4993 write_bmpx_struct *wbms;
4994 if(fsp->wbmpx_ptr != NULL)
4995 wbms = fsp->wbmpx_ptr; /* Use an existing struct */
4996 else
4997 wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
4999 if(!wbms) {
5000 DEBUG(0,("Out of memory in reply_readmpx\n"));
5001 END_PROFILE(SMBwriteBmpx);
5002 return(ERROR_DOS(ERRSRV,ERRnoresource));
5004 wbms->wr_mode = write_through;
5005 wbms->wr_discard = False; /* No errors yet */
5006 wbms->wr_total_written = nwritten;
5007 wbms->wr_errclass = 0;
5008 wbms->wr_error = 0;
5009 fsp->wbmpx_ptr = wbms;
5012 /* We are returning successfully, set the message type back to
5013 SMBwritebmpx */
5014 SCVAL(outbuf,smb_com,SMBwriteBmpx);
5016 outsize = set_message(outbuf,1,0,True);
5018 SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
5020 DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
5021 fsp->fnum, (int)numtowrite, (int)nwritten ) );
5023 if (write_through && tcount==nwritten) {
5024 /* We need to send both a primary and a secondary response */
5025 smb_setlen(outbuf,outsize - 4);
5026 if (!send_smb(smbd_server_fd(),outbuf))
5027 exit_server("reply_writebmpx: send_smb failed.");
5029 /* Now the secondary */
5030 outsize = set_message(outbuf,1,0,True);
5031 SCVAL(outbuf,smb_com,SMBwritec);
5032 SSVAL(outbuf,smb_vwv0,nwritten);
5035 END_PROFILE(SMBwriteBmpx);
5036 return(outsize);
5039 /****************************************************************************
5040 Reply to a SMBwritebs (write block multiplex secondary) request.
5041 ****************************************************************************/
5043 int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
5045 size_t numtowrite;
5046 ssize_t nwritten = -1;
5047 int outsize = 0;
5048 SMB_OFF_T startpos;
5049 size_t tcount;
5050 BOOL write_through;
5051 int smb_doff;
5052 char *data;
5053 write_bmpx_struct *wbms;
5054 BOOL send_response = False;
5055 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
5056 START_PROFILE(SMBwriteBs);
5058 CHECK_FSP(fsp,conn);
5059 CHECK_WRITE(fsp);
5061 tcount = SVAL(inbuf,smb_vwv1);
5062 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
5063 numtowrite = SVAL(inbuf,smb_vwv6);
5064 smb_doff = SVAL(inbuf,smb_vwv7);
5066 data = smb_base(inbuf) + smb_doff;
5068 /* We need to send an SMBwriteC response, not an SMBwritebs */
5069 SCVAL(outbuf,smb_com,SMBwritec);
5071 /* This fd should have an auxiliary struct attached,
5072 check that it does */
5073 wbms = fsp->wbmpx_ptr;
5074 if(!wbms) {
5075 END_PROFILE(SMBwriteBs);
5076 return(-1);
5079 /* If write through is set we can return errors, else we must cache them */
5080 write_through = wbms->wr_mode;
5082 /* Check for an earlier error */
5083 if(wbms->wr_discard) {
5084 END_PROFILE(SMBwriteBs);
5085 return -1; /* Just discard the packet */
5088 nwritten = write_file(fsp,data,startpos,numtowrite);
5090 if(lp_syncalways(SNUM(conn)) || write_through)
5091 sync_file(conn,fsp);
5093 if (nwritten < (ssize_t)numtowrite) {
5094 if(write_through) {
5095 /* We are returning an error - we can delete the aux struct */
5096 SAFE_FREE(wbms);
5097 fsp->wbmpx_ptr = NULL;
5098 END_PROFILE(SMBwriteBs);
5099 return(ERROR_DOS(ERRHRD,ERRdiskfull));
5101 END_PROFILE(SMBwriteBs);
5102 return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
5105 /* Increment the total written, if this matches tcount
5106 we can discard the auxiliary struct (hurrah !) and return a writeC */
5107 wbms->wr_total_written += nwritten;
5108 if(wbms->wr_total_written >= tcount) {
5109 if (write_through) {
5110 outsize = set_message(outbuf,1,0,True);
5111 SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
5112 send_response = True;
5115 SAFE_FREE(wbms);
5116 fsp->wbmpx_ptr = NULL;
5119 if(send_response) {
5120 END_PROFILE(SMBwriteBs);
5121 return(outsize);
5124 END_PROFILE(SMBwriteBs);
5125 return(-1);
5128 /****************************************************************************
5129 Reply to a SMBgetattrE.
5130 ****************************************************************************/
5132 int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
5134 SMB_STRUCT_STAT sbuf;
5135 int outsize = 0;
5136 int mode;
5137 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
5138 START_PROFILE(SMBgetattrE);
5140 outsize = set_message(outbuf,11,0,True);
5142 if(!fsp || (fsp->conn != conn)) {
5143 END_PROFILE(SMBgetattrE);
5144 return ERROR_DOS(ERRDOS,ERRbadfid);
5147 /* Do an stat on this file */
5149 if(fsp_stat(fsp, &sbuf)) {
5150 END_PROFILE(SMBgetattrE);
5151 return(UNIXERROR(ERRDOS,ERRnoaccess));
5154 mode = dos_mode(conn,fsp->fsp_name,&sbuf);
5156 /* Convert the times into dos times. Set create
5157 * date to be last modify date as UNIX doesn't save
5158 * this.
5161 put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
5162 put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
5163 put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
5164 if (mode & aDIR) {
5165 SIVAL(outbuf,smb_vwv6,0);
5166 SIVAL(outbuf,smb_vwv8,0);
5167 } else {
5168 SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
5169 SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
5171 SSVAL(outbuf,smb_vwv10, mode);
5173 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
5175 END_PROFILE(SMBgetattrE);
5176 return(outsize);