****************************************************************************/
static void overflow_attack(int len)
{
- if( DEBUGLVL( 0 ) )
- {
- dbgtext( "ERROR: Invalid password length %d.\n", len );
- dbgtext( "Your machine may be under attack by someone " );
- dbgtext( "attempting to exploit an old bug.\n" );
- dbgtext( "Attack was from IP = %s.\n", client_connection_addr() );
- }
+ if (DEBUGLVL(0))
+ {
+ dbgtext("ERROR: Invalid password length %d.\n", len);
+ dbgtext("Your machine may be under attack by someone ");
+ dbgtext("attempting to exploit an old bug.\n");
+ dbgtext("Attack was from IP = %s.\n",
+ client_connection_addr());
+ }
exit_server("possible attack");
}
/****************************************************************************
reply to an special message
****************************************************************************/
-int reply_special(char *inbuf,char *outbuf)
+int reply_special(char *inbuf, char *outbuf)
{
int outsize = 4;
- int msg_type = CVAL(inbuf,0);
- int msg_flags = CVAL(inbuf,1);
- pstring name1,name2;
+ int msg_type = CVAL(inbuf, 0);
+ int msg_flags = CVAL(inbuf, 1);
+ pstring name1, name2;
extern fstring remote_machine;
extern fstring local_machine;
int len;
char name_type = 0;
-
+
*name1 = *name2 = 0;
-
- bzero(outbuf,smb_size);
- smb_setlen(outbuf,0);
-
- DEBUG(20,("NBT message\n"));
+ bzero(outbuf, smb_size);
+
+ smb_setlen(outbuf, 0);
+
+ DEBUG(20, ("NBT message\n"));
dump_data(20, inbuf, smb_len(inbuf));
- switch (msg_type) {
- case 0x81: /* session request */
- CVAL(outbuf,0) = 0x82;
- CVAL(outbuf,3) = 0;
- if (name_len(inbuf+4) > 50 ||
- name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
- DEBUG(0,("Invalid name length in session request\n"));
- return(0);
- }
- name_extract(inbuf,4,name1);
- name_extract(inbuf,4 + name_len(inbuf + 4),name2);
- DEBUG(2,("netbios connect: name1=%s name2=%s\n",
- name1,name2));
-
- fstrcpy(remote_machine,name2);
- remote_machine[15] = 0;
- trim_string(remote_machine," "," ");
- strlower(remote_machine);
-
- fstrcpy(local_machine,name1);
- len = strlen(local_machine);
- if (len == 16) {
- name_type = local_machine[15];
- local_machine[15] = 0;
- }
- trim_string(local_machine," "," ");
- strlower(local_machine);
+ switch (msg_type)
+ {
+ case 0x81: /* session request */
+ CVAL(outbuf, 0) = 0x82;
+ CVAL(outbuf, 3) = 0;
+ if (name_len(inbuf + 4) > 50 ||
+ name_len(inbuf + 4 + name_len(inbuf + 4)) > 50)
+ {
+ DEBUG(0,
+ ("Invalid name length in session request\n"));
+ return (0);
+ }
+ name_extract(inbuf, 4, name1);
+ name_extract(inbuf, 4 + name_len(inbuf + 4), name2);
+ DEBUG(2, ("netbios connect: name1=%s name2=%s\n",
+ name1, name2));
+
+ fstrcpy(remote_machine, name2);
+ remote_machine[15] = 0;
+ trim_string(remote_machine, " ", " ");
+ strlower(remote_machine);
+
+ fstrcpy(local_machine, name1);
+ len = strlen(local_machine);
+ if (len == 16)
+ {
+ name_type = local_machine[15];
+ local_machine[15] = 0;
+ }
+ trim_string(local_machine, " ", " ");
+ strlower(local_machine);
+
+ if (name_type == 'R')
+ {
+ /* We are being asked for a pathworks session ---
+ no thanks! */
+ CVAL(outbuf, 0) = 0x83;
+ break;
+ }
+
+ add_session_user(remote_machine);
+
+ reload_services(True);
+ reopen_logs();
+
+ if (lp_status(-1))
+ {
+ claim_connection(NULL, "STATUS.", MAXSTATUS,
+ True);
+ }
- if (name_type == 'R') {
- /* We are being asked for a pathworks session ---
- no thanks! */
- CVAL(outbuf, 0) = 0x83;
break;
- }
- add_session_user(remote_machine);
+ case 0x89: /* session keepalive request
+ (some old clients produce this?) */
+ CVAL(outbuf, 0) = 0x85;
+ CVAL(outbuf, 3) = 0;
+ break;
- reload_services(True);
- reopen_logs();
+ case 0x82: /* positive session response */
+ case 0x83: /* negative session response */
+ case 0x84: /* retarget session response */
+ DEBUG(0, ("Unexpected session response\n"));
+ break;
- if (lp_status(-1)) {
- claim_connection(NULL,"STATUS.",MAXSTATUS,True);
- }
+ case 0x85: /* session keepalive */
+ default:
+ return (0);
+ }
+
+ DEBUG(5, ("init msg_type=0x%x msg_flags=0x%x\n",
+ msg_type, msg_flags));
- break;
-
- case 0x89: /* session keepalive request
- (some old clients produce this?) */
- CVAL(outbuf,0) = 0x85;
- CVAL(outbuf,3) = 0;
- break;
-
- case 0x82: /* positive session response */
- case 0x83: /* negative session response */
- case 0x84: /* retarget session response */
- DEBUG(0,("Unexpected session response\n"));
- break;
-
- case 0x85: /* session keepalive */
- default:
- return(0);
- }
-
- DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
- msg_type, msg_flags));
-
- return(outsize);
+ return (outsize);
}
/*******************************************************************
work out what error to give to a failed connection
********************************************************************/
-static int connection_error(char *inbuf,char *outbuf,int ecode)
+static int connection_error(char *inbuf, char *outbuf, int ecode)
{
- if (ecode == ERRnoipc) {
- return(ERROR(ERRDOS,ERRnoipc));
+ if (ecode == ERRnoipc)
+ {
+ return (ERROR(ERRDOS, ERRnoipc));
}
- return(ERROR(ERRSRV,ecode));
+ return (ERROR(ERRSRV, ecode));
}
/****************************************************************************
parse a share descriptor string
****************************************************************************/
-static void parse_connect(char *p,char *service,char *user,
- char *password,int *pwlen,char *dev)
+static void parse_connect(char *p, char *service, char *user,
+ char *password, int *pwlen, char *dev)
{
- char *p2;
-
- DEBUG(4,("parsing connect string %s\n",p));
-
- p2 = strrchr(p,'\\');
- if (p2 == NULL)
- fstrcpy(service,p);
- else
- fstrcpy(service,p2+1);
-
- p += strlen(p) + 2;
-
- fstrcpy(password,p);
- *pwlen = strlen(password);
-
- p += strlen(p) + 2;
-
- fstrcpy(dev,p);
-
- *user = 0;
- p = strchr(service,'%');
- if (p != NULL)
- {
- *p = 0;
- fstrcpy(user,p+1);
- }
+ char *p2;
+
+ DEBUG(4, ("parsing connect string %s\n", p));
+
+ p2 = strrchr(p, '\\');
+ if (p2 == NULL)
+ fstrcpy(service, p);
+ else
+ fstrcpy(service, p2 + 1);
+
+ p += strlen(p) + 2;
+
+ fstrcpy(password, p);
+ *pwlen = strlen(password);
+
+ p += strlen(p) + 2;
+
+ fstrcpy(dev, p);
+
+ *user = 0;
+ p = strchr(service, '%');
+ if (p != NULL)
+ {
+ *p = 0;
+ fstrcpy(user, p + 1);
+ }
}
/****************************************************************************
reply to a tcon
****************************************************************************/
-int reply_tcon(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_tcon(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
{
pstring service;
pstring user;
pstring password;
pstring dev;
int outsize = 0;
- uint16 vuid = SVAL(inbuf,smb_uid);
- int pwlen=0;
+ uint16 vuid = SVAL(inbuf, smb_uid);
+ int pwlen = 0;
int ecode = -1;
*service = *user = *password = *dev = 0;
- parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
+ parse_connect(smb_buf(inbuf) + 1, service, user, password, &pwlen,
+ dev);
map_nt_and_unix_username(global_myworkgroup, user, user, NULL);
- conn = make_connection(service,user,global_myworkgroup, password,pwlen,dev,vuid,&ecode);
-
- if (!conn) {
- return(connection_error(inbuf,outbuf,ecode));
- }
-
- outsize = set_message(outbuf,2,0,True);
- SSVAL(outbuf,smb_vwv0,max_recv);
- SSVAL(outbuf,smb_vwv1,conn->cnum);
- SSVAL(outbuf,smb_tid,conn->cnum);
-
- DEBUG(3,("tcon service=%s user=%s cnum=%d\n",
- service, user, conn->cnum));
-
- return(outsize);
+ conn =
+ make_connection(service, user, global_myworkgroup, password,
+ pwlen, dev, vuid, &ecode);
+
+ if (!conn)
+ {
+ return (connection_error(inbuf, outbuf, ecode));
+ }
+
+ outsize = set_message(outbuf, 2, 0, True);
+ SSVAL(outbuf, smb_vwv0, max_recv);
+ SSVAL(outbuf, smb_vwv1, conn->cnum);
+ SSVAL(outbuf, smb_tid, conn->cnum);
+
+ DEBUG(3, ("tcon service=%s user=%s cnum=%d\n",
+ service, user, conn->cnum));
+
+ return (outsize);
}
/****************************************************************************
reply to a tcon and X
****************************************************************************/
-int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+int reply_tcon_and_X(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
{
pstring service;
pstring user;
pstring password;
pstring devicename;
int ecode = -1;
- uint16 vuid = SVAL(inbuf,smb_uid);
- int passlen = SVAL(inbuf,smb_vwv3);
+ uint16 vuid = SVAL(inbuf, smb_uid);
+ int passlen = SVAL(inbuf, smb_vwv3);
char *path;
char *p;
- BOOL doencrypt = SMBENCRYPT();
-
+ BOOL doencrypt = SMBENCRYPT();
+
*service = *user = *password = *devicename = 0;
/* we might have to close an old one */
- if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
- close_cnum(conn,vuid);
+ if ((SVAL(inbuf, smb_vwv2) & 0x1) && conn)
+ {
+ close_cnum(conn, vuid);
}
- if (passlen > MAX_PASS_LEN) {
+ if (passlen > MAX_PASS_LEN)
+ {
overflow_attack(passlen);
}
-
- memcpy(password,smb_buf(inbuf),passlen);
- password[passlen]=0;
+
+ memcpy(password, smb_buf(inbuf), passlen);
+ password[passlen] = 0;
path = smb_buf(inbuf) + passlen;
- if (passlen != 24) {
- if (strequal(password," "))
+ if (passlen != 24)
+ {
+ if (strequal(password, " "))
*password = 0;
passlen = strlen(password);
}
*password = 0;
}
- fstrcpy(service,path+2);
- p = strchr(service,'\\');
+ fstrcpy(service, path + 2);
+ p = strchr(service, '\\');
if (!p)
- return(ERROR(ERRSRV,ERRinvnetname));
+ return (ERROR(ERRSRV, ERRinvnetname));
*p = 0;
- fstrcpy(service,p+1);
- p = strchr(service,'%');
- if (p) {
+ fstrcpy(service, p + 1);
+ p = strchr(service, '%');
+ if (p)
+ {
*p++ = 0;
- fstrcpy(user,p);
+ fstrcpy(user, p);
}
- StrnCpy(devicename,path + strlen(path) + 1,6);
- DEBUG(4,("Got device type %s\n",devicename));
+ StrnCpy(devicename, path + strlen(path) + 1, 6);
+ DEBUG(4, ("Got device type %s\n", devicename));
map_nt_and_unix_username(global_myworkgroup, user, user, NULL);
- conn = make_connection(service,user,global_myworkgroup, password,passlen,devicename,vuid,&ecode);
-
+ conn =
+ make_connection(service, user, global_myworkgroup, password,
+ passlen, devicename, vuid, &ecode);
+
if (!conn)
- return(connection_error(inbuf,outbuf,ecode));
+ return (connection_error(inbuf, outbuf, ecode));
- if (Protocol < PROTOCOL_NT1) {
- set_message(outbuf,2,strlen(devicename)+1,True);
- pstrcpy(smb_buf(outbuf),devicename);
- } else {
+ if (Protocol < PROTOCOL_NT1)
+ {
+ set_message(outbuf, 2, strlen(devicename) + 1, True);
+ pstrcpy(smb_buf(outbuf), devicename);
+ }
+ else
+ {
char *fsname = lp_fstype(SNUM(conn));
- set_message(outbuf,3,3,True);
+ set_message(outbuf, 3, 3, True);
p = smb_buf(outbuf);
- pstrcpy(p,devicename); p = skip_string(p,1); /* device name */
- pstrcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
-
- set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
-
+ pstrcpy(p, devicename);
+ p = skip_string(p, 1); /* device name */
+ pstrcpy(p, fsname);
+ p = skip_string(p, 1); /* filesystem type e.g NTFS */
+
+ set_message(outbuf, 3, PTR_DIFF(p, smb_buf(outbuf)), False);
+
/* what does setting this bit do? It is set by NT4 and
may affect the ability to autorun mounted cdroms */
- SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS);
+ SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS);
}
-
- DEBUG(3,("tconX service=%s user=%s\n",
- service, user));
-
+
+ DEBUG(3, ("tconX service=%s user=%s\n", service, user));
+
/* set the incoming and outgoing tid to the just created one */
- SSVAL(inbuf,smb_tid,conn->cnum);
- SSVAL(outbuf,smb_tid,conn->cnum);
+ SSVAL(inbuf, smb_tid, conn->cnum);
+ SSVAL(outbuf, smb_tid, conn->cnum);
- return chain_reply(inbuf,outbuf,length,bufsize);
+ return chain_reply(inbuf, outbuf, length, bufsize);
}
/****************************************************************************
reply to an unknown type
****************************************************************************/
-int reply_unknown(char *inbuf,char *outbuf)
+int reply_unknown(char *inbuf, char *outbuf)
{
int type;
- type = CVAL(inbuf,smb_com);
-
- DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
- smb_fn_name(type), type, type));
-
- return(ERROR(ERRSRV,ERRunknownsmb));
+ type = CVAL(inbuf, smb_com);
+
+ DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
+ smb_fn_name(type), type, type));
+
+ return (ERROR(ERRSRV, ERRunknownsmb));
}
/****************************************************************************
reply to an ioctl
****************************************************************************/
-int reply_ioctl(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_ioctl(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
{
- DEBUG(3,("ignoring ioctl\n"));
+ DEBUG(3, ("ignoring ioctl\n"));
#if 0
/* we just say it succeeds and hope its all OK.
some day it would be nice to interpret them individually */
- return set_message(outbuf,1,0,True);
+ return set_message(outbuf, 1, 0, True);
#else
- return(ERROR(ERRSRV,ERRnosupport));
+ return (ERROR(ERRSRV, ERRnosupport));
#endif
}
/****************************************************************************
always return an error: it's just a matter of which one...
****************************************************************************/
-static int session_trust_account(connection_struct *conn,
- char *inbuf, char *outbuf,
- char *user, char *domain,
- char *smb_passwd, int smb_passlen,
- char *smb_nt_passwd, int smb_nt_passlen)
+static int session_trust_account(connection_struct * conn,
+ char *inbuf, char *outbuf,
+ char *user, char *domain,
+ char *smb_passwd, int smb_passlen,
+ char *smb_nt_passwd, int smb_nt_passlen)
{
uchar last_chal[8];
uint32 status = 0x0;
if (lp_security() != SEC_USER)
{
- DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user));
+ DEBUG(0,
+ ("session_trust_account: Trust account %s only supported with security = user\n",
+ user));
SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
+ return (ERROR(0, 0xc0000000 | NT_STATUS_LOGON_FAILURE));
}
if (last_challenge(last_chal))
NET_USER_INFO_3 info3;
ZERO_STRUCT(info3);
status = check_domain_security(user, domain,
- last_chal,
- (uchar *)smb_passwd, smb_passlen,
- (uchar *)smb_nt_passwd, smb_nt_passlen,
- &info3);
+ last_chal,
+ (uchar *) smb_passwd,
+ smb_passlen,
+ (uchar *) smb_nt_passwd,
+ smb_nt_passlen, &info3);
}
else
{
- status = 0xc0000000|NT_STATUS_LOGON_FAILURE;
+ status = 0xc0000000 | NT_STATUS_LOGON_FAILURE;
}
if (status == 0x0)
{
- status = 0xc0000000|NT_STATUS_LOGON_FAILURE;
+ status = 0xc0000000 | NT_STATUS_LOGON_FAILURE;
}
SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
reply to a session setup command
****************************************************************************/
-int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+int reply_sesssetup_and_X(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
{
- uint16 sess_vuid;
- NET_USER_INFO_3 info3;
- int gid;
- int uid;
- int smb_bufsize;
- int smb_apasslen = 0;
- pstring smb_apasswd;
- int smb_ntpasslen = 0;
- pstring smb_ntpasswd;
- pstring user;
- pstring orig_user;
- BOOL guest=False;
- static BOOL done_sesssetup = False;
- BOOL doencrypt = SMBENCRYPT();
- char *domain = "";
-
- ZERO_STRUCT(info3);
-
- *smb_apasswd = 0;
- *smb_ntpasswd = 0;
-
- smb_bufsize = SVAL(inbuf,smb_vwv2);
-
- if (Protocol < PROTOCOL_NT1)
- {
- smb_apasslen = SVAL(inbuf,smb_vwv7);
- if (smb_apasslen > MAX_PASS_LEN)
- {
- overflow_attack(smb_apasslen);
- }
-
- memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
- smb_apasswd[smb_apasslen] = 0;
- pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
-
- if (!doencrypt && (lp_security() != SEC_SERVER)) {
- smb_apasslen = strlen(smb_apasswd);
- }
-
- if (lp_server_ntlmv2() == True)
- {
- DEBUG(1,("NTLMv2-only accepted with NT LANMAN 1.0 and above.\n\
-user %s attempted down-level SMB connection\n", user));
- return(ERROR(ERRSRV,ERRbadpw));
- }
- }
- else
- {
- uint16 passlen1 = SVAL(inbuf,smb_vwv7);
- uint16 passlen2 = SVAL(inbuf,smb_vwv8);
- enum remote_arch_types ra_type = get_remote_arch();
- char *p = smb_buf(inbuf);
-
- DEBUG(10,("passlen1: %d passlen2: %d\n", passlen1, passlen2));
-
- global_client_caps = IVAL(inbuf,smb_vwv11);
-
- /* client_caps is used as final determination if client is NT or Win95.
- This is needed to return the correct error codes in some
- circumstances.
- */
-
- if(ra_type == RA_WINNT || ra_type == RA_WIN95)
- {
- if(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))
- set_remote_arch( RA_WINNT);
- else
- set_remote_arch( RA_WIN95);
- }
-
- if (passlen1 != 24 && passlen2 <= 24)
- doencrypt = False;
-
- if (passlen1 > MAX_PASS_LEN) {
- overflow_attack(passlen1);
- }
-
- passlen1 = MIN(passlen1, MAX_PASS_LEN);
- passlen2 = MIN(passlen2, MAX_PASS_LEN);
-
- if(!doencrypt) {
- /* both Win95 and WinNT stuff up the password lengths for
- non-encrypting systems. Uggh.
-
- if passlen1==24 its a win95 system, and its setting the
- password length incorrectly. Luckily it still works with the
- default code because Win95 will null terminate the password
- anyway
-
- if passlen1>0 and passlen2>0 then maybe its a NT box and its
- setting passlen2 to some random value which really stuffs
- things up. we need to fix that one.
-
- LKCLXXXX: the random value can be random 16 bit. old test
- used to have ... && passlen <= 24) which of course fails
- most of the time.
- */
-
- if (passlen1 > 0 && passlen2 > 0 && passlen2 != 1)
- passlen2 = 0;
- }
-
- if (doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
- /* Save the lanman2 password and the NT md4 password. */
- smb_apasslen = passlen1;
- memcpy(smb_apasswd,p,smb_apasslen);
- smb_apasswd[smb_apasslen] = 0;
- smb_ntpasslen = passlen2;
- memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
- smb_ntpasswd[smb_ntpasslen] = 0;
- } else {
- /* we use the first password that they gave */
- smb_apasslen = passlen1;
- StrnCpy(smb_apasswd,p,smb_apasslen);
-
- /* trim the password */
- smb_apasslen = strlen(smb_apasswd);
-
- /* wfwg sometimes uses a space instead of a null */
- if (strequal(smb_apasswd," ")) {
- smb_apasslen = 0;
+ uint16 sess_vuid;
+ NET_USER_INFO_3 info3;
+ int gid;
+ int uid;
+ int smb_bufsize;
+ int smb_apasslen = 0;
+ pstring smb_apasswd;
+ int smb_ntpasslen = 0;
+ pstring smb_ntpasswd;
+ pstring user;
+ pstring orig_user;
+ BOOL guest = False;
+ static BOOL done_sesssetup = False;
+ BOOL doencrypt = SMBENCRYPT();
+ char *domain = "";
+
+ ZERO_STRUCT(info3);
+
*smb_apasswd = 0;
- }
- }
-
- if (passlen2 == 0 && smb_apasslen == 0 && ra_type == RA_WIN95)
- {
- /* work-around for win95 NULL sessions, where NULL password is
- actually put in the data stream before the domain name etc */
- p++;
- }
- else
- {
- p += passlen1 + passlen2;
- }
-
- fstrcpy(user,p); p = skip_string(p,1);
- domain = p;
-
- DEBUG(3,("passlen: %d %d Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
- passlen1, passlen2, domain, skip_string(p,1), skip_string(p,2)));
- }
-
- DEBUG(3,("sesssetupX:name=[%s]\n",user));
-
- /* If name ends in $ then I think it's asking about whether a */
- /* computer with that name (minus the $) has access. For now */
- /* say yes to everything ending in $. */
- if ((user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24))
- {
- return session_trust_account(conn, inbuf, outbuf, user, domain,
- smb_apasswd, smb_apasslen,
- smb_ntpasswd, smb_ntpasslen);
- }
-
- /* If no username is sent use the guest account */
- if (!*user)
- {
- pstrcpy(user,lp_guestaccount(-1));
- /* If no user and no password then set guest flag. */
- if( *smb_apasswd == 0)
- guest = True;
- }
-
- strlower(user);
- /*
- * In share level security, only overwrite sesssetup_use if
- * it's a non null-session share. Helps keep %U and %G
- * working.
- */
-
- if((lp_security() != SEC_SHARE) || (*user && !guest))
- pstrcpy(sesssetup_user,user);
- reload_services(True);
-
- /*
- * Save the username before mapping. We will use
- * the original username sent to us for security=server
- * and security=domain checking.
- */
-
- pstrcpy( orig_user, user);
-
- map_nt_and_unix_username(domain, user, user, NULL);
-
- add_session_user(user);
-
- /*
- * Check if the given username was the guest user with no password.
- */
-
- if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
- guest = True;
+ *smb_ntpasswd = 0;
+
+ smb_bufsize = SVAL(inbuf, smb_vwv2);
+
+ if (Protocol < PROTOCOL_NT1)
+ {
+ smb_apasslen = SVAL(inbuf, smb_vwv7);
+ if (smb_apasslen > MAX_PASS_LEN)
+ {
+ overflow_attack(smb_apasslen);
+ }
+
+ memcpy(smb_apasswd, smb_buf(inbuf), smb_apasslen);
+ smb_apasswd[smb_apasslen] = 0;
+ pstrcpy(user, smb_buf(inbuf) + smb_apasslen);
+
+ if (!doencrypt && (lp_security() != SEC_SERVER))
+ {
+ smb_apasslen = strlen(smb_apasswd);
+ }
+
+ if (lp_server_ntlmv2() == True)
+ {
+ DEBUG(1,
+ ("NTLMv2-only accepted with NT LANMAN 1.0 and above.\n\
+user %s attempted down-level SMB connection\n",
+ user));
+ return (ERROR(ERRSRV, ERRbadpw));
+ }
+ }
+ else
+ {
+ uint16 passlen1 = SVAL(inbuf, smb_vwv7);
+ uint16 passlen2 = SVAL(inbuf, smb_vwv8);
+ enum remote_arch_types ra_type = get_remote_arch();
+ char *p = smb_buf(inbuf);
+
+ DEBUG(10,
+ ("passlen1: %d passlen2: %d\n", passlen1, passlen2));
+
+ global_client_caps = IVAL(inbuf, smb_vwv11);
+
+ /* client_caps is used as final determination if client is NT or Win95.
+ This is needed to return the correct error codes in some
+ circumstances.
+ */
+
+ if (ra_type == RA_WINNT || ra_type == RA_WIN95)
+ {
+ if (global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))
+ set_remote_arch(RA_WINNT);
+ else
+ set_remote_arch(RA_WIN95);
+ }
+
+ if (passlen1 != 24 && passlen2 <= 24)
+ doencrypt = False;
+
+ if (passlen1 > MAX_PASS_LEN)
+ {
+ overflow_attack(passlen1);
+ }
+
+ passlen1 = MIN(passlen1, MAX_PASS_LEN);
+ passlen2 = MIN(passlen2, MAX_PASS_LEN);
+
+ if (!doencrypt)
+ {
+ /* both Win95 and WinNT stuff up the password lengths for
+ non-encrypting systems. Uggh.
+
+ if passlen1==24 its a win95 system, and its setting the
+ password length incorrectly. Luckily it still works with the
+ default code because Win95 will null terminate the password
+ anyway
+
+ if passlen1>0 and passlen2>0 then maybe its a NT box and its
+ setting passlen2 to some random value which really stuffs
+ things up. we need to fix that one.
+
+ LKCLXXXX: the random value can be random 16 bit. old test
+ used to have ... && passlen <= 24) which of course fails
+ most of the time.
+ */
+
+ if (passlen1 > 0 && passlen2 > 0 && passlen2 != 1)
+ passlen2 = 0;
+ }
+
+ if (doencrypt
+ || ((lp_security() == SEC_SERVER)
+ || (lp_security() == SEC_DOMAIN)))
+ {
+ /* Save the lanman2 password and the NT md4 password. */
+ smb_apasslen = passlen1;
+ memcpy(smb_apasswd, p, smb_apasslen);
+ smb_apasswd[smb_apasslen] = 0;
+ smb_ntpasslen = passlen2;
+ memcpy(smb_ntpasswd, p + passlen1, smb_ntpasslen);
+ smb_ntpasswd[smb_ntpasslen] = 0;
+ }
+ else
+ {
+ /* we use the first password that they gave */
+ smb_apasslen = passlen1;
+ StrnCpy(smb_apasswd, p, smb_apasslen);
+
+ /* trim the password */
+ smb_apasslen = strlen(smb_apasswd);
+
+ /* wfwg sometimes uses a space instead of a null */
+ if (strequal(smb_apasswd, " "))
+ {
+ smb_apasslen = 0;
+ *smb_apasswd = 0;
+ }
+ }
+
+ if (passlen2 == 0 && smb_apasslen == 0 && ra_type == RA_WIN95)
+ {
+ /* work-around for win95 NULL sessions, where NULL password is
+ actually put in the data stream before the domain name etc */
+ p++;
+ }
+ else
+ {
+ p += passlen1 + passlen2;
+ }
+
+ fstrcpy(user, p);
+ p = skip_string(p, 1);
+ domain = p;
+
+ DEBUG(3,
+ ("passlen: %d %d Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
+ passlen1, passlen2, domain, skip_string(p, 1),
+ skip_string(p, 2)));
+ }
+
+ DEBUG(3, ("sesssetupX:name=[%s]\n", user));
+
+ /* If name ends in $ then I think it's asking about whether a */
+ /* computer with that name (minus the $) has access. For now */
+ /* say yes to everything ending in $. */
+ if ((user[strlen(user) - 1] == '$') && (smb_apasslen == 24)
+ && (smb_ntpasslen == 24))
+ {
+ return session_trust_account(conn, inbuf, outbuf, user,
+ domain, smb_apasswd,
+ smb_apasslen, smb_ntpasswd,
+ smb_ntpasslen);
+ }
+
+ /* If no username is sent use the guest account */
+ if (!*user)
+ {
+ pstrcpy(user, lp_guestaccount(-1));
+ /* If no user and no password then set guest flag. */
+ if (*smb_apasswd == 0)
+ guest = True;
+ }
+
+ strlower(user);
+ /*
+ * In share level security, only overwrite sesssetup_use if
+ * it's a non null-session share. Helps keep %U and %G
+ * working.
+ */
+
+ if ((lp_security() != SEC_SHARE) || (*user && !guest))
+ pstrcpy(sesssetup_user, user);
+ reload_services(True);
+
+ /*
+ * Save the username before mapping. We will use
+ * the original username sent to us for security=server
+ * and security=domain checking.
+ */
+
+ pstrcpy(orig_user, user);
+
+ map_nt_and_unix_username(domain, user, user, NULL);
+
+ add_session_user(user);
+
+ /*
+ * Check if the given username was the guest user with no password.
+ */
+
+ if (!guest && strequal(user, lp_guestaccount(-1))
+ && (*smb_apasswd == 0))
+ guest = True;
if (!guest && !check_hosts_equiv(user))
{
* security=domain.
*/
- DEBUG(10,("Checking SMB password, user %s domain %s\n",
+ DEBUG(10, ("Checking SMB password, user %s domain %s\n",
user, domain));
- if(!password_ok(orig_user, domain,
- smb_apasswd,smb_apasslen,
- smb_ntpasswd,smb_ntpasslen,
- NULL, &info3))
+ if (!password_ok(orig_user, domain,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen, NULL, &info3))
{
- DEBUG(0,("SMB LM/NT Password did not match!\n"));
+ DEBUG(0, ("SMB LM/NT Password did not match!\n"));
- if (lp_security() >= SEC_USER)
+ if (lp_security() >= SEC_USER)
{
if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
- return(ERROR(ERRSRV,ERRbadpw));
+ return (ERROR(ERRSRV, ERRbadpw));
- if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
+ if (lp_map_to_guest() ==
+ MAP_TO_GUEST_ON_BAD_USER)
{
- if (Get_Pwnam(user,True))
- return(ERROR(ERRSRV,ERRbadpw));
+ if (Get_Pwnam(user, True))
+ return (ERROR
+ (ERRSRV, ERRbadpw));
}
/*
*/
}
- if (*smb_apasswd || !Get_Pwnam(user,True))
- pstrcpy(user,lp_guestaccount(-1));
- DEBUG(3,("Registered username %s for guest access\n",user));
+ if (*smb_apasswd || !Get_Pwnam(user, True))
+ pstrcpy(user, lp_guestaccount(-1));
+ DEBUG(3,
+ ("Registered username %s for guest access\n",
+ user));
guest = True;
}
}
- if (!Get_Pwnam(user,True)) {
- DEBUG(3,("No such user %s - using guest account\n",user));
- pstrcpy(user,lp_guestaccount(-1));
- guest = True;
- }
-
- if (!strequal(user,lp_guestaccount(-1)) &&
- lp_servicenumber(user) < 0)
- {
- int homes = lp_servicenumber(HOMES_NAME);
- char *home = get_unixhome_dir(user);
- if (homes >= 0 && home)
- {
- pstring home_dir;
- fstrcpy(home_dir, home);
- lp_add_home(user,homes,home_dir);
- }
- }
-
- /* it's ok - setup a reply */
- if (Protocol < PROTOCOL_NT1) {
- set_message(outbuf,3,0,True);
- } else {
- char *p;
- set_message(outbuf,3,3,True);
- p = smb_buf(outbuf);
- pstrcpy(p,"Unix"); p = skip_string(p,1);
- pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1);
- pstrcpy(p,global_myworkgroup); p = skip_string(p,1);
- set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
- /* perhaps grab OS version here?? */
- }
-
- /* Set the correct uid in the outgoing and incoming packets
- We will use this on future requests to determine which
- user we should become.
- */
- {
- const struct passwd *pw = Get_Pwnam(user,False);
- if (!pw) {
- DEBUG(1,("Username %s is invalid on this system\n",user));
- return(ERROR(ERRSRV,ERRbadpw));
- }
- gid = pw->pw_gid;
- uid = pw->pw_uid;
- }
-
- if (guest)
- SSVAL(outbuf,smb_vwv2,1);
-
- /* register the name and uid as being validated, so further connections
- to a uid can get through without a password, on the same VC */
- sess_vuid = register_vuid(getpid(), uid,gid,user,sesssetup_user,guest,&info3);
-
- SSVAL(outbuf,smb_uid,sess_vuid);
- SSVAL(inbuf,smb_uid,sess_vuid);
-
- if (!done_sesssetup)
- max_send = MIN(max_send,smb_bufsize);
-
- DEBUG(6,("Client requested max send size of %d\n", max_send));
-
- done_sesssetup = True;
-
- return chain_reply(inbuf,outbuf,length,bufsize);
-}
+ if (!Get_Pwnam(user, True))
+ {
+ DEBUG(3, ("No such user %s - using guest account\n", user));
+ pstrcpy(user, lp_guestaccount(-1));
+ guest = True;
+ }
+ if (!strequal(user, lp_guestaccount(-1)) &&
+ lp_servicenumber(user) < 0)
+ {
+ int homes = lp_servicenumber(HOMES_NAME);
+ char *home = get_unixhome_dir(user);
+ if (homes >= 0 && home)
+ {
+ pstring home_dir;
+ fstrcpy(home_dir, home);
+ lp_add_home(user, homes, home_dir);
+ }
+ }
-/****************************************************************************
- reply to a chkpth
-****************************************************************************/
-int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = 0;
- int mode;
- pstring name;
- BOOL ok = False;
- BOOL bad_path = False;
- SMB_STRUCT_STAT st;
-
- pstrcpy(name,smb_buf(inbuf) + 1);
- if (!unix_dfs_convert(name,conn,0,&bad_path,&st))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- mode = SVAL(inbuf,smb_vwv0);
-
- if (check_name(name,conn)) {
- if(VALID_STAT(st))
- ok = S_ISDIR(st.st_mode);
- else
- ok = dos_directory_exist(name,NULL);
- }
-
- if (!ok)
- {
- /* We special case this - as when a Windows machine
- is parsing a path is steps through the components
- one at a time - if a component fails it expects
- ERRbadpath, not ERRbadfile.
- */
- if(errno == ENOENT)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
+ /* it's ok - setup a reply */
+ if (Protocol < PROTOCOL_NT1)
+ {
+ set_message(outbuf, 3, 0, True);
+ }
+ else
+ {
+ char *p;
+ set_message(outbuf, 3, 3, True);
+ p = smb_buf(outbuf);
+ pstrcpy(p, "Unix");
+ p = skip_string(p, 1);
+ pstrcpy(p, "Samba ");
+ pstrcat(p, VERSION);
+ p = skip_string(p, 1);
+ pstrcpy(p, global_myworkgroup);
+ p = skip_string(p, 1);
+ set_message(outbuf, 3, PTR_DIFF(p, smb_buf(outbuf)), False);
+ /* perhaps grab OS version here?? */
+ }
-#if 0
- /* Ugly - NT specific hack - maybe not needed ? (JRA) */
- if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
- (get_remote_arch() == RA_WINNT))
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbaddirectory;
- }
-#endif
+ /* Set the correct uid in the outgoing and incoming packets
+ We will use this on future requests to determine which
+ user we should become.
+ */
+ {
+ const struct passwd *pw = Get_Pwnam(user, False);
+ if (!pw)
+ {
+ DEBUG(1,
+ ("Username %s is invalid on this system\n",
+ user));
+ return (ERROR(ERRSRV, ERRbadpw));
+ }
+ gid = pw->pw_gid;
+ uid = pw->pw_uid;
+ }
- return(UNIXERROR(ERRDOS,ERRbadpath));
- }
+ if (guest)
+ SSVAL(outbuf, smb_vwv2, 1);
- outsize = set_message(outbuf,0,0,True);
+ /* register the name and uid as being validated, so further connections
+ to a uid can get through without a password, on the same VC */
+ sess_vuid =
+ register_vuid(getpid(), uid, gid, user, sesssetup_user, guest,
+ &info3);
- DEBUG(3,("chkpth %s mode=%d\n", name, mode));
+ SSVAL(outbuf, smb_uid, sess_vuid);
+ SSVAL(inbuf, smb_uid, sess_vuid);
- return(outsize);
-}
+ if (!done_sesssetup)
+ max_send = MIN(max_send, smb_bufsize);
+ DEBUG(6, ("Client requested max send size of %d\n", max_send));
-/****************************************************************************
- reply to a getatr
-****************************************************************************/
-int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- pstring fname;
- int outsize = 0;
- SMB_STRUCT_STAT sbuf;
- BOOL ok = False;
- int mode=0;
- SMB_OFF_T size=0;
- time_t mtime=0;
- BOOL bad_path = False;
-
- pstrcpy(fname,smb_buf(inbuf) + 1);
-
- /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
- under WfWg - weird! */
- if (! (*fname))
- {
- mode = aHIDDEN | aDIR;
- if (!CAN_WRITE(conn)) mode |= aRONLY;
- size = 0;
- mtime = 0;
- ok = True;
- }
- else
- {
- if (!unix_dfs_convert(fname,conn,0,&bad_path,&sbuf))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- if (check_name(fname,conn))
- {
- if (VALID_STAT(sbuf) || conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf) == 0)
- {
- mode = dos_mode(conn,fname,&sbuf);
- size = sbuf.st_size;
- mtime = sbuf.st_mtime;
- if (mode & aDIR)
- size = 0;
- ok = True;
- }
- else
- DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
- }
- }
-
- if (!ok)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
-
- return(UNIXERROR(ERRDOS,ERRbadfile));
- }
-
- outsize = set_message(outbuf,10,0,True);
-
- SSVAL(outbuf,smb_vwv0,mode);
- if(lp_dos_filetime_resolution(SNUM(conn)) )
- put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
- else
- put_dos_date3(outbuf,smb_vwv1,mtime);
- SIVAL(outbuf,smb_vwv3,(uint32)size);
-
- if (Protocol >= PROTOCOL_NT1) {
- char *p = strrchr(fname,'/');
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- if (!p) p = fname;
- if (!is_8_3(fname, True))
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
- }
-
- DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
-
- return(outsize);
+ done_sesssetup = True;
+
+ return chain_reply(inbuf, outbuf, length, bufsize);
}
/****************************************************************************
- reply to a setatr
+ reply to a chkpth
****************************************************************************/
-int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_chkpth(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- pstring fname;
- int outsize = 0;
- BOOL ok=False;
- int mode;
- time_t mtime;
- SMB_STRUCT_STAT st;
- BOOL bad_path = False;
-
- pstrcpy(fname,smb_buf(inbuf) + 1);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,&st))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- mode = SVAL(inbuf,smb_vwv0);
- mtime = make_unix_date3(inbuf+smb_vwv1);
-
- if (VALID_STAT_OF_DIR(st) || dos_directory_exist(fname,NULL))
- mode |= aDIR;
- if (check_name(fname,conn))
- ok = (file_chmod(conn,fname,mode,NULL) == 0);
- if (ok)
- ok = set_filetime(conn,fname,mtime);
-
- if (!ok)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
-
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- outsize = set_message(outbuf,0,0,True);
-
- DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
-
- return(outsize);
-}
+ int outsize = 0;
+ int mode;
+ pstring name;
+ BOOL ok = False;
+ BOOL bad_path = False;
+ SMB_STRUCT_STAT st;
+
+ pstrcpy(name, smb_buf(inbuf) + 1);
+ if (!unix_dfs_convert(name, conn, 0, &bad_path, &st))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+ mode = SVAL(inbuf, smb_vwv0);
-/****************************************************************************
- reply to a dskattr
-****************************************************************************/
-int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = 0;
- SMB_BIG_UINT dfree,dsize,bsize;
-
- conn->vfs_ops.disk_free(".",&bsize,&dfree,&dsize);
-
- outsize = set_message(outbuf,5,0,True);
-
- SSVAL(outbuf,smb_vwv0,dsize);
- SSVAL(outbuf,smb_vwv1,bsize/512);
- SSVAL(outbuf,smb_vwv2,512);
- SSVAL(outbuf,smb_vwv3,dfree);
-
- DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
-
- return(outsize);
-}
+ if (check_name(name, conn))
+ {
+ if (VALID_STAT(st))
+ ok = S_ISDIR(st.st_mode);
+ else
+ ok = dos_directory_exist(name, NULL);
+ }
+ if (!ok)
+ {
+ /* We special case this - as when a Windows machine
+ is parsing a path is steps through the components
+ one at a time - if a component fails it expects
+ ERRbadpath, not ERRbadfile.
+ */
+ if (errno == ENOENT)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
-/****************************************************************************
- reply to a search
- Can be called from SMBsearch, SMBffirst or SMBfunique.
-****************************************************************************/
-int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- pstring mask;
- pstring directory;
- pstring fname;
- SMB_OFF_T size;
- int mode;
- time_t date;
- int dirtype;
- int outsize = 0;
- int numentries = 0;
- BOOL finished = False;
- int maxentries;
- int i;
- char *p;
- BOOL ok = False;
- int status_len;
- char *path;
- char status[21];
- int dptr_num= -1;
- BOOL check_descend = False;
- BOOL expect_close = False;
- BOOL can_open = True;
- BOOL bad_path = False;
-
- *mask = *directory = *fname = 0;
-
- /* If we were called as SMBffirst then we must expect close. */
- if(CVAL(inbuf,smb_com) == SMBffirst)
- expect_close = True;
-
- outsize = set_message(outbuf,1,3,True);
- maxentries = SVAL(inbuf,smb_vwv0);
- dirtype = SVAL(inbuf,smb_vwv1);
- path = smb_buf(inbuf) + 1;
- status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
-
-
- /* dirtype &= ~aDIR; */
-
- DEBUG(5,("path=%s status_len=%d\n",path,status_len));
-
-
- if (status_len == 0)
- {
- pstring dir2;
-
- pstrcpy(directory,smb_buf(inbuf)+1);
- pstrcpy(dir2,smb_buf(inbuf)+1);
- if (!unix_dfs_convert(directory,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- unix_format(dir2);
-
- if (!check_name(directory,conn))
- can_open = False;
-
- p = strrchr(dir2,'/');
- if (p == NULL)
- {
- pstrcpy(mask,dir2);
- *dir2 = 0;
- }
- else
- {
- *p = 0;
- pstrcpy(mask,p+1);
- }
-
- p = strrchr(directory,'/');
- if (!p)
- *directory = 0;
- else
- *p = 0;
-
- if (strlen(directory) == 0)
- pstrcpy(directory,"./");
- bzero(status,21);
- CVAL(status,0) = dirtype;
- }
- else
- {
- memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
- memcpy(mask,status+1,11);
- mask[11] = 0;
- dirtype = CVAL(status,0) & 0x1F;
- conn->dirptr = dptr_fetch(status+12,&dptr_num);
- if (!conn->dirptr)
- goto SearchEmpty;
- string_set(&conn->dirpath,dptr_path(dptr_num));
- if (!case_sensitive)
- strnorm(mask);
- }
-
- /* turn strings of spaces into a . */
- {
- trim_string(mask,NULL," ");
- if ((p = strrchr(mask,' ')))
- {
- fstring ext;
- fstrcpy(ext,p+1);
- *p = 0;
- trim_string(mask,NULL," ");
- pstrcat(mask,".");
- pstrcat(mask,ext);
- }
- }
-
- /* Convert the formatted mask. (This code lives in trans2.c) */
- mask_convert(mask);
-
- {
- int skip;
- p = mask;
- while(*p)
- {
- if((skip = skip_multibyte_char( *p )) != 0 )
- {
- p += skip;
- }
- else
- {
- if (*p != '?' && *p != '*' && !isdoschar(*p))
- {
- DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
- *p = '?';
- }
- p++;
- }
- }
- }
-
- if (!strchr(mask,'.') && strlen(mask)>8)
- {
- fstring tmp;
- fstrcpy(tmp,&mask[8]);
- mask[8] = '.';
- mask[9] = 0;
- pstrcat(mask,tmp);
- }
-
- DEBUG(5,("mask=%s directory=%s\n",mask,directory));
-
- if (can_open)
- {
- p = smb_buf(outbuf) + 3;
-
- ok = True;
-
- if (status_len == 0)
- {
- dptr_num = dptr_create(conn,directory,expect_close,SVAL(inbuf,smb_pid));
- if (dptr_num < 0)
- {
- if(dptr_num == -2)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return (UNIXERROR(ERRDOS,ERRnofids));
- }
- return(ERROR(ERRDOS,ERRnofids));
- }
- }
-
- DEBUG(4,("dptr_num is %d\n",dptr_num));
-
- if (ok)
- {
- if ((dirtype&0x1F) == aVOLID)
- {
- memcpy(p,status,21);
- make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
- dptr_fill(p+12,dptr_num);
- if (dptr_zero(p+12) && (status_len==0))
- numentries = 1;
- else
- numentries = 0;
- p += DIR_STRUCT_SIZE;
- }
- else
- {
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- conn->dirpath,lp_dontdescend(SNUM(conn))));
- if (in_list(conn->dirpath,
- lp_dontdescend(SNUM(conn)),True))
- check_descend = True;
-
- for (i=numentries;(i<maxentries) && !finished;i++)
+#if 0
+ /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+ if ((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
+ (get_remote_arch() == RA_WINNT))
{
- finished =
- !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
- if (!finished)
- {
- memcpy(p,status,21);
- make_dir_struct(p,mask,fname,size,mode,date);
- dptr_fill(p+12,dptr_num);
- numentries++;
- }
- p += DIR_STRUCT_SIZE;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbaddirectory;
}
- }
- }
- }
-
-
- SearchEmpty:
-
- if (numentries == 0 || !ok)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- }
-
- /* If we were called as SMBffirst with smb_search_id == NULL
- and no entries were found then return error and close dirptr
- (X/Open spec) */
-
- if(ok && expect_close && numentries == 0 && status_len == 0)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- /* Also close the dptr - we know it's gone */
- dptr_close(dptr_num);
- }
-
- /* If we were called as SMBfunique, then we can close the dirptr now ! */
- if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
- dptr_close(dptr_num);
-
- SSVAL(outbuf,smb_vwv0,numentries);
- SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
- CVAL(smb_buf(outbuf),0) = 5;
- SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
-
- if (Protocol >= PROTOCOL_NT1) {
- uint16 flg2 = SVAL(outbuf,smb_flg2);
- SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
- }
-
- outsize += DIR_STRUCT_SIZE*numentries;
- smb_setlen(outbuf,outsize - 4);
-
- if ((! *directory) && dptr_path(dptr_num))
- slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
-
- DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask, directory, dirtype, numentries, maxentries ) );
-
- return(outsize);
+#endif
+
+ return (UNIXERROR(ERRDOS, ERRbadpath));
+ }
+
+ outsize = set_message(outbuf, 0, 0, True);
+
+ DEBUG(3, ("chkpth %s mode=%d\n", name, mode));
+
+ return (outsize);
}
/****************************************************************************
- reply to a fclose (stop directory search)
+ reply to a getatr
****************************************************************************/
-int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_getatr(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- int outsize = 0;
- int status_len;
- char *path;
- char status[21];
- int dptr_num= -1;
-
- outsize = set_message(outbuf,1,0,True);
- path = smb_buf(inbuf) + 1;
- status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
-
-
- if (status_len == 0)
- return(ERROR(ERRSRV,ERRsrverror));
-
- memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
+ pstring fname;
+ int outsize = 0;
+ SMB_STRUCT_STAT sbuf;
+ BOOL ok = False;
+ int mode = 0;
+ SMB_OFF_T size = 0;
+ time_t mtime = 0;
+ BOOL bad_path = False;
+
+ pstrcpy(fname, smb_buf(inbuf) + 1);
+
+ /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
+ under WfWg - weird! */
+ if (!(*fname))
+ {
+ mode = aHIDDEN | aDIR;
+ if (!CAN_WRITE(conn))
+ mode |= aRONLY;
+ size = 0;
+ mtime = 0;
+ ok = True;
+ }
+ else
+ {
+ if (!unix_dfs_convert(fname, conn, 0, &bad_path, &sbuf))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR
+ (0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+ if (check_name(fname, conn))
+ {
+ if (VALID_STAT(sbuf)
+ || conn->vfs_ops.stat(dos_to_unix(fname, False),
+ &sbuf) == 0)
+ {
+ mode = dos_mode(conn, fname, &sbuf);
+ size = sbuf.st_size;
+ mtime = sbuf.st_mtime;
+ if (mode & aDIR)
+ size = 0;
+ ok = True;
+ }
+ else
+ DEBUG(3,
+ ("stat of %s failed (%s)\n", fname,
+ strerror(errno)));
+ }
+ }
- if(dptr_fetch(status+12,&dptr_num)) {
- /* Close the dptr - we know it's gone */
- dptr_close(dptr_num);
- }
+ if (!ok)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
- SSVAL(outbuf,smb_vwv0,0);
+ return (UNIXERROR(ERRDOS, ERRbadfile));
+ }
- DEBUG(3,("search close\n"));
+ outsize = set_message(outbuf, 10, 0, True);
- return(outsize);
-}
+ SSVAL(outbuf, smb_vwv0, mode);
+ if (lp_dos_filetime_resolution(SNUM(conn)))
+ put_dos_date3(outbuf, smb_vwv1, mtime & ~1);
+ else
+ put_dos_date3(outbuf, smb_vwv1, mtime);
+ SIVAL(outbuf, smb_vwv3, (uint32) size);
+ if (Protocol >= PROTOCOL_NT1)
+ {
+ char *p = strrchr(fname, '/');
+ uint16 flg2 = SVAL(outbuf, smb_flg2);
+ if (!p)
+ p = fname;
+ if (!is_8_3(fname, True))
+ SSVAL(outbuf, smb_flg2, flg2 | 0x40); /* IS_LONG_NAME */
+ }
-/****************************************************************************
- reply to an open
-****************************************************************************/
+ DEBUG(3,
+ ("getatr name=%s mode=%d size=%d\n", fname, mode,
+ (uint32) size));
-int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- pstring fname;
- int outsize = 0;
- int fmode=0;
- int share_mode;
- SMB_OFF_T size = 0;
- time_t mtime=0;
- mode_t unixmode;
- int rmode=0;
- SMB_STRUCT_STAT sbuf;
- BOOL bad_path = False;
- files_struct *fsp;
- int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
-
- share_mode = SVAL(inbuf,smb_vwv0);
-
- pstrcpy(fname,smb_buf(inbuf)+1);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- fsp = file_new();
- if (!fsp)
- return(ERROR(ERRSRV,ERRnofids));
-
- if (!check_name(fname,conn))
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- unixmode = unix_mode(conn,aARCH);
-
- open_file_shared(fsp, conn, fname, share_mode,
- (FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN),
- unixmode, oplock_request, &rmode, NULL);
-
- if (!fsp->open)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
- close_file(fsp,False);
- return(ERROR(ERRDOS,ERRnoaccess));
- }
-
- size = sbuf.st_size;
- fmode = dos_mode(conn,fname,&sbuf);
- mtime = sbuf.st_mtime;
-
- if (fmode & aDIR) {
- DEBUG(3,("attempt to open a directory %s\n",fname));
- close_file(fsp,False);
- return(ERROR(ERRDOS,ERRnoaccess));
- }
-
- outsize = set_message(outbuf,7,0,True);
- SSVAL(outbuf,smb_vwv0,fsp->fnum);
- SSVAL(outbuf,smb_vwv1,fmode);
- if(lp_dos_filetime_resolution(SNUM(conn)) )
- put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
- else
- put_dos_date3(outbuf,smb_vwv2,mtime);
- SIVAL(outbuf,smb_vwv4,(uint32)size);
- SSVAL(outbuf,smb_vwv6,rmode);
-
- if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
- }
-
- if(fsp->granted_oplock)
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
- return(outsize);
+ return (outsize);
}
/****************************************************************************
- reply to an open and X
+ reply to a setatr
****************************************************************************/
-int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+int reply_setatr(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- pstring fname;
- int smb_mode = SVAL(inbuf,smb_vwv3);
- int smb_attr = SVAL(inbuf,smb_vwv5);
- /* Breakout the oplock request bits so we can set the
- reply bits separately. */
- BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
- BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
- BOOL oplock_request = ex_oplock_request | core_oplock_request;
-#if 0
- int open_flags = SVAL(inbuf,smb_vwv2);
- int smb_sattr = SVAL(inbuf,smb_vwv4);
- uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
-#endif
- int smb_ofun = SVAL(inbuf,smb_vwv8);
- mode_t unixmode;
- SMB_OFF_T size=0;
- int fmode=0,mtime=0,rmode=0;
- SMB_STRUCT_STAT sbuf;
- int smb_action = 0;
- BOOL bad_path = False;
- files_struct *fsp;
-
- /* If it's an IPC, pass off the pipe handler. */
- if (IS_IPC(conn) && lp_nt_pipe_support() && lp_security() != SEC_SHARE)
- {
- return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
- }
-
- /* XXXX we need to handle passed times, sattr and flags */
-
- pstrcpy(fname,smb_buf(inbuf));
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- fsp = file_new();
- if (!fsp)
- return(ERROR(ERRSRV,ERRnofids));
-
- if (!check_name(fname,conn))
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- unixmode = unix_mode(conn,smb_attr | aARCH);
-
- open_file_shared(fsp, conn, fname, smb_mode, smb_ofun, unixmode,
- oplock_request, &rmode, &smb_action);
-
- if (!fsp->open)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
- close_file(fsp,False);
- return(ERROR(ERRDOS,ERRnoaccess));
- }
-
- size = sbuf.st_size;
- fmode = dos_mode(conn,fname,&sbuf);
- mtime = sbuf.st_mtime;
- if (fmode & aDIR) {
- close_file(fsp,False);
- return(ERROR(ERRDOS,ERRnoaccess));
- }
-
- /* If the caller set the extended oplock request bit
- and we granted one (by whatever means) - set the
- correct bit for extended oplock reply.
- */
-
- if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
- smb_action |= EXTENDED_OPLOCK_GRANTED;
- }
-
- if(ex_oplock_request && fsp->granted_oplock) {
- smb_action |= EXTENDED_OPLOCK_GRANTED;
- }
-
- /* If the caller set the core oplock request bit
- and we granted one (by whatever means) - set the
- correct bit for core oplock reply.
- */
-
- if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
- }
-
- if(core_oplock_request && fsp->granted_oplock) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
- }
-
- set_message(outbuf,15,0,True);
- SSVAL(outbuf,smb_vwv2,fsp->fnum);
- SSVAL(outbuf,smb_vwv3,fmode);
- if(lp_dos_filetime_resolution(SNUM(conn)) )
- put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
- else
- put_dos_date3(outbuf,smb_vwv4,mtime);
- SIVAL(outbuf,smb_vwv6,(uint32)size);
- SSVAL(outbuf,smb_vwv8,rmode);
- SSVAL(outbuf,smb_vwv11,smb_action);
-
- return chain_reply(inbuf,outbuf,length,bufsize);
-}
+ pstring fname;
+ int outsize = 0;
+ BOOL ok = False;
+ int mode;
+ time_t mtime;
+ SMB_STRUCT_STAT st;
+ BOOL bad_path = False;
+ pstrcpy(fname, smb_buf(inbuf) + 1);
+ if (!unix_dfs_convert(fname, conn, 0, &bad_path, &st))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
-/****************************************************************************
- reply to a SMBulogoffX
-****************************************************************************/
-int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
-{
- uint16 vuid = SVAL(inbuf,smb_uid);
- vuser_key key;
- user_struct *vuser = NULL;
- key.pid = conn != NULL ? conn->smbd_pid : getpid();
- key.vuid = vuid;
- vuser = get_valid_user_struct(&key);
+ mode = SVAL(inbuf, smb_vwv0);
+ mtime = make_unix_date3(inbuf + smb_vwv1);
- if (vuser == 0)
- {
- DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
- }
+ if (VALID_STAT_OF_DIR(st) || dos_directory_exist(fname, NULL))
+ mode |= aDIR;
+ if (check_name(fname, conn))
+ ok = (file_chmod(conn, fname, mode, NULL) == 0);
+ if (ok)
+ ok = set_filetime(conn, fname, mtime);
- /* in user level security we are supposed to close any files
- open by this user */
- if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
- file_close_user(vuid);
- }
+ if (!ok)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
- invalidate_vuid(&key);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
- set_message(outbuf,2,0,True);
+ outsize = set_message(outbuf, 0, 0, True);
- DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
+ DEBUG(3, ("setatr name=%s mode=%d\n", fname, mode));
- return chain_reply(inbuf,outbuf,length,bufsize);
+ return (outsize);
}
/****************************************************************************
- reply to a mknew or a create
+ reply to a dskattr
****************************************************************************/
-int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_dskattr(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- pstring fname;
- int com;
- int outsize = 0;
- int createmode;
- mode_t unixmode;
- int ofun = 0;
- BOOL bad_path = False;
- files_struct *fsp;
- int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
-
- com = SVAL(inbuf,smb_com);
-
- createmode = SVAL(inbuf,smb_vwv0);
- pstrcpy(fname,smb_buf(inbuf)+1);
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- if (createmode & aVOLID)
- {
- DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
- }
-
- unixmode = unix_mode(conn,createmode);
-
- fsp = file_new();
- if (!fsp)
- return(ERROR(ERRSRV,ERRnofids));
-
- if (!check_name(fname,conn))
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- if(com == SMBmknew)
- {
- /* We should fail if file exists. */
- ofun = 0x10;
- }
- else
- {
- /* SMBcreate - Create if file doesn't exist, truncate if it does. */
- ofun = 0x12;
- }
-
- /* Open file in dos compatibility share mode. */
- open_file_shared(fsp, conn, fname,
- SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
- ofun, unixmode, oplock_request, NULL, NULL);
-
- if (!fsp->open)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,fsp->fnum);
-
- if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
- }
-
- if(fsp->granted_oplock)
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
-
- DEBUG( 2, ( "new file %s\n", fname ) );
- DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
- fname, fsp->fd_ptr->fd, createmode, (int)unixmode ) );
-
- return(outsize);
-}
-
+ int outsize = 0;
+ SMB_BIG_UINT dfree, dsize, bsize;
-/****************************************************************************
- reply to a create temporary file
-****************************************************************************/
-int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- pstring fname;
- pstring fname2;
- int outsize = 0;
- int createmode;
- mode_t unixmode;
- BOOL bad_path = False;
- files_struct *fsp;
- int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
-
- createmode = SVAL(inbuf,smb_vwv0);
- pstrcpy(fname,smb_buf(inbuf)+1);
- pstrcat(fname,"/TMXXXXXX");
- if (!unix_dfs_convert(fname,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- unixmode = unix_mode(conn,createmode);
-
- fsp = file_new();
- if (fsp)
- return(ERROR(ERRSRV,ERRnofids));
-
- if (!check_name(fname,conn))
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- pstrcpy(fname2,(char *)mktemp(fname));
-
- /* Open file in dos compatibility share mode. */
- /* We should fail if file exists. */
- open_file_shared(fsp,conn,fname2,
- SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
- (FILE_CREATE_IF_NOT_EXIST | FILE_EXISTS_FAIL),
- unixmode, oplock_request, NULL, NULL);
-
- if (!fsp->open)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- outsize = set_message(outbuf,1,2 + strlen(fname2),True);
- SSVAL(outbuf,smb_vwv0,fsp->fnum);
- CVAL(smb_buf(outbuf),0) = 4;
- pstrcpy(smb_buf(outbuf) + 1,fname2);
-
- if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
- }
-
- if(fsp->granted_oplock)
- CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
-
- DEBUG( 2, ( "created temp file %s\n", fname2 ) );
- DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
- fname2, fsp->fd_ptr->fd, createmode, (int)unixmode ) );
-
- return(outsize);
-}
+ conn->vfs_ops.disk_free(".", &bsize, &dfree, &dsize);
+ outsize = set_message(outbuf, 5, 0, True);
-/*******************************************************************
-check if a user is allowed to delete a file
-********************************************************************/
-static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
-{
- SMB_STRUCT_STAT sbuf;
- int fmode;
-
- if (!CAN_WRITE(conn)) return(False);
-
- if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
- fmode = dos_mode(conn,fname,&sbuf);
- if (fmode & aDIR) return(False);
- if (!lp_delete_readonly(SNUM(conn))) {
- if (fmode & aRONLY) return(False);
- }
- if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
- return(False);
- if (!check_file_sharing(conn,fname,False)) return(False);
- return(True);
-}
+ SSVAL(outbuf, smb_vwv0, dsize);
+ SSVAL(outbuf, smb_vwv1, bsize / 512);
+ SSVAL(outbuf, smb_vwv2, 512);
+ SSVAL(outbuf, smb_vwv3, dfree);
-/****************************************************************************
- reply to a unlink
-****************************************************************************/
-int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = 0;
- pstring name;
- int dirtype;
- pstring directory;
- pstring mask;
- char *p;
- int count=0;
- int error = ERRnoaccess;
- BOOL has_wild;
- BOOL exists=False;
- BOOL bad_path = False;
-
- *directory = *mask = 0;
-
- dirtype = SVAL(inbuf,smb_vwv0);
-
- pstrcpy(name,smb_buf(inbuf) + 1);
-
- DEBUG(3,("reply_unlink : %s\n",name));
-
- if (!unix_dfs_convert(name,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- p = strrchr(name,'/');
- if (!p) {
- pstrcpy(directory,"./");
- pstrcpy(mask,name);
- } else {
- *p = 0;
- pstrcpy(directory,name);
- pstrcpy(mask,p+1);
- }
-
- if (is_mangled(mask))
- check_mangled_cache( mask );
-
- has_wild = strchr(mask,'*') || strchr(mask,'?');
-
- if (!has_wild) {
- pstrcat(directory,"/");
- pstrcat(directory,mask);
- if (can_delete(directory,conn,dirtype) &&
- !conn->vfs_ops.unlink(dos_to_unix(directory,False)))
- count++;
- if (!count)
- exists = vfs_file_exist(conn,dos_to_unix(directory,False),NULL);
- } else {
- void *dirptr = NULL;
- char *dname;
-
- if (check_name(directory,conn))
- dirptr = OpenDir(conn, directory, True);
-
- /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
- the pattern matches against the long name, otherwise the short name
- We don't implement this yet XXXX
- */
-
- if (dirptr)
- {
- error = ERRbadfile;
-
- if (strequal(mask,"????????.???"))
- pstrcpy(mask,"*");
+ DEBUG(3, ("dskattr dfree=%d\n", (unsigned int)dfree));
- while ((dname = ReadDirName(dirptr)))
- {
- pstring fname;
- pstrcpy(fname,dname);
-
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
-
- error = ERRnoaccess;
- slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
- if (!can_delete(fname,conn,dirtype)) continue;
- if (!conn->vfs_ops.unlink(dos_to_unix(fname,False))) count++;
- DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
- }
- CloseDir(dirptr);
- }
- }
-
- if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,error));
- }
- }
-
- outsize = set_message(outbuf,0,0,True);
-
- return(outsize);
+ return (outsize);
}
/****************************************************************************
- reply to a readbraw (core+ protocol)
+ reply to a search
+ Can be called from SMBsearch, SMBffirst or SMBfunique.
****************************************************************************/
-int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
+int reply_search(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- size_t maxcount,mincount;
- size_t nread = 0;
- SMB_OFF_T startpos;
- char *header = outbuf;
- ssize_t ret=0;
- files_struct *fsp;
-
- /*
- * Special check if an oplock break has been issued
- * and the readraw request croses on the wire, we must
- * return a zero length response here.
- */
-
- if(global_oplock_break)
- {
- _smb_setlen(header,0);
- transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
- DEBUG(5,("readbraw - oplock break finished\n"));
- return -1;
- }
-
- fsp = file_fsp(inbuf,smb_vwv0);
-
- startpos = IVAL(inbuf,smb_vwv1);
-#ifdef LARGE_SMB_OFF_T
- if(CVAL(inbuf,smb_wct) == 10) {
- /*
- * This is a large offset (64 bit) read.
- */
- startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
- if(startpos < 0) {
- DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
- (double)startpos ));
- _smb_setlen(header,0);
- transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
- return(-1);
- }
- }
-#endif /* LARGE_SMB_OFF_T */
- maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
- mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
-
- /* ensure we don't overrun the packet size */
- maxcount = MIN(65535,maxcount);
- maxcount = MAX(mincount,maxcount);
-
- if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
- DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fsp->fnum));
- _smb_setlen(header,0);
- transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
- return(-1);
- }
-
- if (!is_locked(fsp,conn,maxcount,startpos, F_RDLCK))
- {
- SMB_OFF_T size = fsp->size;
- SMB_OFF_T sizeneeded = startpos + maxcount;
-
- if (size < sizeneeded)
- {
- SMB_STRUCT_STAT st;
- if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&st) == 0)
- size = st.st_size;
- if (!fsp->can_write)
- fsp->size = size;
- }
-
- nread = MIN(maxcount,(size - startpos));
- }
-
- if (nread < mincount)
- nread = 0;
-
- DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
- fsp->fnum, (double)startpos,
- maxcount, mincount, nread ) );
-
-#if UNSAFE_READRAW
- {
- BOOL seek_fail = False;
- int predict=0;
- _smb_setlen(header,nread);
-
-#if USE_READ_PREDICTION
- if (!fsp->can_write)
- predict = read_predict(fsp, fsp->fd_ptr->fd,startpos,header+4,NULL,nread);
-#endif /* USE_READ_PREDICTION */
-
- if ((nread-predict) > 0) {
- if(conn->vfs_ops.seek(fsp,startpos + predict) == -1) {
- DEBUG(0,("reply_readbraw: ERROR: seek_file failed.\n"));
- ret = 0;
- seek_fail = True;
- }
- }
+ pstring mask;
+ pstring directory;
+ pstring fname;
+ SMB_OFF_T size;
+ int mode;
+ time_t date;
+ int dirtype;
+ int outsize = 0;
+ int numentries = 0;
+ BOOL finished = False;
+ int maxentries;
+ int i;
+ char *p;
+ BOOL ok = False;
+ int status_len;
+ char *path;
+ char status[21];
+ int dptr_num = -1;
+ BOOL check_descend = False;
+ BOOL expect_close = False;
+ BOOL can_open = True;
+ BOOL bad_path = False;
- if(!seek_fail)
- ret = (ssize_t)vfs_transfer_file(-1, fsp->fd_ptr->fd, Client, NULL,
- (SMB_OFF_T)(nread-predict),header,4+predict,
- startpos+predict);
- }
+ *mask = *directory = *fname = 0;
- if (ret != nread+4)
- DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
- fsp->fsp_name,startpos,nread,ret));
+ /* If we were called as SMBffirst then we must expect close. */
+ if (CVAL(inbuf, smb_com) == SMBffirst)
+ expect_close = True;
-#else /* UNSAFE_READRAW */
- ret = read_file(fsp,header+4,startpos,nread);
- if (ret < mincount) ret = 0;
+ outsize = set_message(outbuf, 1, 3, True);
+ maxentries = SVAL(inbuf, smb_vwv0);
+ dirtype = SVAL(inbuf, smb_vwv1);
+ path = smb_buf(inbuf) + 1;
+ status_len = SVAL(smb_buf(inbuf), 3 + strlen(path));
- _smb_setlen(header,ret);
- transfer_file(0,Client,0,header,4+ret,0);
-#endif /* UNSAFE_READRAW */
- DEBUG(5,("readbraw finished\n"));
- return -1;
-}
+ /* dirtype &= ~aDIR; */
+ DEBUG(5, ("path=%s status_len=%d\n", path, status_len));
-/****************************************************************************
- reply to a lockread (core+ protocol)
-****************************************************************************/
-int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
-{
- ssize_t nread = -1;
- char *data;
- int outsize = 0;
- SMB_OFF_T startpos;
- size_t numtoread;
- int eclass;
- uint32 ecode;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- CHECK_FSP(fsp,conn);
- CHECK_READ(fsp);
- CHECK_ERROR(fsp);
-
- numtoread = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
-
- outsize = set_message(outbuf,5,3,True);
- numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
- data = smb_buf(outbuf) + 3;
-
- if(!do_lock( fsp, conn, numtoread, startpos, F_RDLCK, &eclass, &ecode)) {
- if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
- /*
- * A blocking lock was requested. Package up
- * this smb into a queued request and push it
- * onto the blocking lock queue.
- */
- if(push_blocking_lock_request(inbuf, length, -1, 0))
- return -1;
- }
- return (ERROR(eclass,ecode));
- }
-
- nread = read_file(fsp,data,startpos,numtoread);
-
- if (nread < 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize += nread;
- SSVAL(outbuf,smb_vwv0,nread);
- SSVAL(outbuf,smb_vwv5,nread+3);
- SSVAL(smb_buf(outbuf),1,nread);
-
- DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
- fsp->fnum, numtoread, nread ) );
-
- return(outsize);
-}
+ if (status_len == 0)
+ {
+ pstring dir2;
-/****************************************************************************
- reply to a read
-****************************************************************************/
-int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- size_t numtoread;
- ssize_t nread = 0;
- char *data;
- SMB_OFF_T startpos;
- int outsize = 0;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- CHECK_FSP(fsp,conn);
- CHECK_READ(fsp);
- CHECK_ERROR(fsp);
-
- numtoread = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
-
- outsize = set_message(outbuf,5,3,True);
- numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
- data = smb_buf(outbuf) + 3;
-
- if (is_locked(fsp,conn,numtoread,startpos, F_RDLCK))
- return(ERROR(ERRDOS,ERRlock));
-
- if (numtoread > 0) {
- nread = read_file(fsp,data,startpos,numtoread);
- }
-
- if (nread < 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize += nread;
- SSVAL(outbuf,smb_vwv0,nread);
- SSVAL(outbuf,smb_vwv5,nread+3);
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,nread);
-
- DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
- fsp->fnum, numtoread, nread ) );
-
- return(outsize);
-}
+ pstrcpy(directory, smb_buf(inbuf) + 1);
+ pstrcpy(dir2, smb_buf(inbuf) + 1);
+ if (!unix_dfs_convert(directory, conn, 0, &bad_path, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR
+ (0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+ unix_format(dir2);
+ if (!check_name(directory, conn))
+ can_open = False;
-/****************************************************************************
- reply to a read and X
-****************************************************************************/
-int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
-{
- files_struct *fsp = file_fsp(inbuf,smb_vwv2);
- SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
- size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
- size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
- ssize_t nread = -1;
- char *data;
+ p = strrchr(dir2, '/');
+ if (p == NULL)
+ {
+ pstrcpy(mask, dir2);
+ *dir2 = 0;
+ }
+ else
+ {
+ *p = 0;
+ pstrcpy(mask, p + 1);
+ }
- /* If it's an IPC, pass off the pipe handler. */
- if (IS_IPC(conn))
- return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
+ p = strrchr(directory, '/');
+ if (!p)
+ *directory = 0;
+ else
+ *p = 0;
- CHECK_FSP(fsp,conn);
- CHECK_READ(fsp);
- CHECK_ERROR(fsp);
+ if (strlen(directory) == 0)
+ pstrcpy(directory, "./");
+ bzero(status, 21);
+ CVAL(status, 0) = dirtype;
+ }
+ else
+ {
+ memcpy(status, smb_buf(inbuf) + 1 + strlen(path) + 4, 21);
+ memcpy(mask, status + 1, 11);
+ mask[11] = 0;
+ dirtype = CVAL(status, 0) & 0x1F;
+ conn->dirptr = dptr_fetch(status + 12, &dptr_num);
+ if (!conn->dirptr)
+ goto SearchEmpty;
+ string_set(&conn->dirpath, dptr_path(dptr_num));
+ if (!case_sensitive)
+ strnorm(mask);
+ }
- set_message(outbuf,12,0,True);
- data = smb_buf(outbuf);
+ /* turn strings of spaces into a . */
+ {
+ trim_string(mask, NULL, " ");
+ if ((p = strrchr(mask, ' ')))
+ {
+ fstring ext;
+ fstrcpy(ext, p + 1);
+ *p = 0;
+ trim_string(mask, NULL, " ");
+ pstrcat(mask, ".");
+ pstrcat(mask, ext);
+ }
+ }
-#ifdef LARGE_SMB_OFF_T
- if(CVAL(inbuf,smb_wct) == 12) {
- /*
- * This is a large offset (64 bit) read.
- */
- startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
- }
-#endif /* LARGE_SMB_OFF_T */
+ /* Convert the formatted mask. (This code lives in trans2.c) */
+ mask_convert(mask);
- if (is_locked(fsp,conn,smb_maxcnt,startpos, F_RDLCK))
- return(ERROR(ERRDOS,ERRlock));
- nread = read_file(fsp,data,startpos,smb_maxcnt);
+ {
+ int skip;
+ p = mask;
+ while (*p)
+ {
+ if ((skip = skip_multibyte_char(*p)) != 0)
+ {
+ p += skip;
+ }
+ else
+ {
+ if (*p != '?' && *p != '*' && !isdoschar(*p))
+ {
+ DEBUG(5,
+ ("Invalid char [%c] in search mask?\n",
+ *p));
+ *p = '?';
+ }
+ p++;
+ }
+ }
+ }
- if (nread < 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- SSVAL(outbuf,smb_vwv5,nread);
- SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
- SSVAL(smb_buf(outbuf),-2,nread);
+ if (!strchr(mask, '.') && strlen(mask) > 8)
+ {
+ fstring tmp;
+ fstrcpy(tmp, &mask[8]);
+ mask[8] = '.';
+ mask[9] = 0;
+ pstrcat(mask, tmp);
+ }
- DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
- fsp->fnum, smb_mincnt, smb_maxcnt, nread ) );
+ DEBUG(5, ("mask=%s directory=%s\n", mask, directory));
- return chain_reply(inbuf,outbuf,length,bufsize);
-}
+ if (can_open)
+ {
+ p = smb_buf(outbuf) + 3;
-/****************************************************************************
- reply to a writebraw (core+ or LANMAN1.0 protocol)
-****************************************************************************/
-int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- ssize_t nwritten=0;
- ssize_t total_written=0;
- size_t numtowrite=0;
- size_t tcount;
- SMB_OFF_T startpos;
- char *data=NULL;
- BOOL write_through;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- int outsize = 0;
-
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
- CHECK_ERROR(fsp);
-
- tcount = IVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv3);
- write_through = BITSETW(inbuf+smb_vwv7,0);
-
- /* We have to deal with slightly different formats depending
- on whether we are using the core+ or lanman1.0 protocol */
- if(Protocol <= PROTOCOL_COREPLUS) {
- numtowrite = SVAL(smb_buf(inbuf),-2);
- data = smb_buf(inbuf);
- } else {
- numtowrite = SVAL(inbuf,smb_vwv10);
- data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
- }
-
- /* force the error type */
- CVAL(inbuf,smb_com) = SMBwritec;
- CVAL(outbuf,smb_com) = SMBwritec;
-
- if (is_locked(fsp,conn,tcount,startpos, F_WRLCK))
- return(ERROR(ERRDOS,ERRlock));
-
- if (seek_file(fsp,startpos) == -1) {
- DEBUG(0,("couldn't seek to %.0f in writebraw\n",(double)startpos));
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- if (numtowrite>0)
- nwritten = write_file(fsp,data,numtowrite);
-
- DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
- fsp->fnum, (double)startpos, numtowrite, nwritten, write_through));
-
- if (nwritten < numtowrite)
- return(UNIXERROR(ERRHRD,ERRdiskfull));
-
- total_written = nwritten;
-
- /* Return a message to the redirector to tell it
- to send more bytes */
- CVAL(outbuf,smb_com) = SMBwritebraw;
- SSVALS(outbuf,smb_vwv0,-1);
- outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
- send_smb(Client,outbuf);
-
- /* Now read the raw data into the buffer and write it */
- if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
- exit_server("secondary writebraw failed");
- }
-
- /* Even though this is not an smb message, smb_len
- returns the generic length of an smb message */
- numtowrite = smb_len(inbuf);
-
- if (tcount > nwritten+numtowrite) {
- DEBUG(3,("Client overestimated the write %d %d %d\n",
- tcount,nwritten,numtowrite));
- }
-
- nwritten = vfs_transfer_file(Client, NULL, -1, fsp,
- (SMB_OFF_T)numtowrite,NULL,0,
- startpos+nwritten);
- total_written += nwritten;
-
- /* Set up outbuf to return the correct return */
- outsize = set_message(outbuf,1,0,True);
- CVAL(outbuf,smb_com) = SMBwritec;
- SSVAL(outbuf,smb_vwv0,total_written);
-
- if (nwritten < (ssize_t)numtowrite) {
- CVAL(outbuf,smb_rcls) = ERRHRD;
- SSVAL(outbuf,smb_err,ERRdiskfull);
- }
-
- if ((lp_syncalways(SNUM(conn)) || write_through) &&
- lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
-
- DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
- fsp->fnum, (double)startpos, numtowrite, total_written));
-
- /* we won't return a status if write through is not selected - this
- follows what WfWg does */
- if (!write_through && total_written==tcount)
- return(-1);
-
- return(outsize);
-}
+ ok = True;
-/****************************************************************************
- reply to a writeunlock (core+)
-****************************************************************************/
-int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- ssize_t nwritten = -1;
- size_t numtowrite;
- SMB_OFF_T startpos;
- char *data;
- int eclass;
- uint32 ecode;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- int outsize = 0;
-
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
- CHECK_ERROR(fsp);
-
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- data = smb_buf(inbuf) + 3;
-
- if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
- return(ERROR(ERRDOS,ERRlock));
-
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- /* The special X/Open SMB protocol handling of
- zero length writes is *NOT* done for
- this call */
- if(numtowrite == 0)
- nwritten = 0;
- else
- nwritten = write_file(fsp,data,numtowrite);
-
- if (lp_syncalways(SNUM(conn)) && lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
-
- if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- if(!do_unlock(fsp, conn, numtowrite, startpos, &eclass, &ecode))
- return(ERROR(eclass,ecode));
-
- outsize = set_message(outbuf,1,0,True);
-
- SSVAL(outbuf,smb_vwv0,nwritten);
-
- DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten ) );
-
- return(outsize);
-}
+ if (status_len == 0)
+ {
+ dptr_num =
+ dptr_create(conn, directory, expect_close,
+ SVAL(inbuf, smb_pid));
+ if (dptr_num < 0)
+ {
+ if (dptr_num == -2)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return (UNIXERROR(ERRDOS, ERRnofids));
+ }
+ return (ERROR(ERRDOS, ERRnofids));
+ }
+ }
-/****************************************************************************
- reply to a write
-****************************************************************************/
-int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,int dum_buffsize)
-{
- size_t numtowrite;
- ssize_t nwritten = -1;
- SMB_OFF_T startpos;
- char *data;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- int outsize = 0;
-
- /* If it's an IPC, pass off the pipe handler. */
- if (IS_IPC(conn))
- return reply_pipe_write(inbuf,outbuf,dum_size,dum_buffsize);
-
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
- CHECK_ERROR(fsp);
-
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- data = smb_buf(inbuf) + 3;
-
- if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
- return(ERROR(ERRDOS,ERRlock));
-
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- /* X/Open SMB protocol says that if smb_vwv1 is
- zero then the file size should be extended or
- truncated to the size given in smb_vwv[2-3] */
- if(numtowrite == 0)
- nwritten = set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T)startpos);
- else
- nwritten = write_file(fsp,data,numtowrite);
-
- if (lp_syncalways(SNUM(conn)) && lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
-
- if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize = set_message(outbuf,1,0,True);
-
- SSVAL(outbuf,smb_vwv0,nwritten);
-
- if (nwritten < (ssize_t)numtowrite) {
- CVAL(outbuf,smb_rcls) = ERRHRD;
- SSVAL(outbuf,smb_err,ERRdiskfull);
- }
-
- DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten));
-
- return(outsize);
-}
+ DEBUG(4, ("dptr_num is %d\n", dptr_num));
+ if (ok)
+ {
+ if ((dirtype & 0x1F) == aVOLID)
+ {
+ memcpy(p, status, 21);
+ make_dir_struct(p, "???????????",
+ volume_label(SNUM(conn)), 0,
+ aVOLID, 0);
+ dptr_fill(p + 12, dptr_num);
+ if (dptr_zero(p + 12) && (status_len == 0))
+ numentries = 1;
+ else
+ numentries = 0;
+ p += DIR_STRUCT_SIZE;
+ }
+ else
+ {
+ DEBUG(8, ("dirpath=<%s> dontdescend=<%s>\n",
+ conn->dirpath,
+ lp_dontdescend(SNUM(conn))));
+ if (in_list
+ (conn->dirpath,
+ lp_dontdescend(SNUM(conn)), True))
+ check_descend = True;
+
+ for (i = numentries;
+ (i < maxentries) && !finished; i++)
+ {
+ finished =
+ !get_dir_entry(conn, mask,
+ dirtype, fname,
+ &size, &mode,
+ &date,
+ check_descend);
+ if (!finished)
+ {
+ memcpy(p, status, 21);
+ make_dir_struct(p, mask,
+ fname, size,
+ mode, date);
+ dptr_fill(p + 12, dptr_num);
+ numentries++;
+ }
+ p += DIR_STRUCT_SIZE;
+ }
+ }
+ }
+ }
-/****************************************************************************
- reply to a write and X
-****************************************************************************/
-int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
-{
- files_struct *fsp = file_fsp(inbuf,smb_vwv2);
- SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
- size_t numtowrite = SVAL(inbuf,smb_vwv10);
- BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
- ssize_t nwritten = -1;
- int smb_doff = SVAL(inbuf,smb_vwv11);
- char *data;
- /* If it's an IPC, pass off the pipe handler. */
- if (IS_IPC(conn))
- return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
+ SearchEmpty:
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
- CHECK_ERROR(fsp);
+ if (numentries == 0 || !ok)
+ {
+ CVAL(outbuf, smb_rcls) = ERRDOS;
+ SSVAL(outbuf, smb_err, ERRnofiles);
+ }
- data = smb_base(inbuf) + smb_doff;
+ /* If we were called as SMBffirst with smb_search_id == NULL
+ and no entries were found then return error and close dirptr
+ (X/Open spec) */
-#ifdef LARGE_SMB_OFF_T
- if(CVAL(inbuf,smb_wct) == 14) {
- /*
- * This is a large offset (64 bit) write.
- */
- startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
- }
-#endif /* LARGE_SMB_OFF_T */
+ if (ok && expect_close && numentries == 0 && status_len == 0)
+ {
+ CVAL(outbuf, smb_rcls) = ERRDOS;
+ SSVAL(outbuf, smb_err, ERRnofiles);
+ /* Also close the dptr - we know it's gone */
+ dptr_close(dptr_num);
+ }
- if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
- return(ERROR(ERRDOS,ERRlock));
-
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- /* X/Open SMB protocol says that, unlike SMBwrite
- if the length is zero then NO truncation is
- done, just a write of zero. To truncate a file,
- use SMBwrite. */
- if(numtowrite == 0)
- nwritten = 0;
- else
- nwritten = write_file(fsp,data,numtowrite);
-
- if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- set_message(outbuf,6,0,True);
-
- SSVAL(outbuf,smb_vwv2,nwritten);
-
- if (nwritten < (ssize_t)numtowrite) {
- CVAL(outbuf,smb_rcls) = ERRHRD;
- SSVAL(outbuf,smb_err,ERRdiskfull);
- }
-
- DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten));
-
- if ((lp_syncalways(SNUM(conn)) || write_through) &&
- lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
-
- return chain_reply(inbuf,outbuf,length,bufsize);
-}
+ /* If we were called as SMBfunique, then we can close the dirptr now ! */
+ if (dptr_num >= 0 && CVAL(inbuf, smb_com) == SMBfunique)
+ dptr_close(dptr_num);
+ SSVAL(outbuf, smb_vwv0, numentries);
+ SSVAL(outbuf, smb_vwv1, 3 + numentries * DIR_STRUCT_SIZE);
+ CVAL(smb_buf(outbuf), 0) = 5;
+ SSVAL(smb_buf(outbuf), 1, numentries * DIR_STRUCT_SIZE);
-/****************************************************************************
- reply to a lseek
-****************************************************************************/
-int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- SMB_OFF_T startpos;
- SMB_OFF_T res= -1;
- int mode,umode;
- int outsize = 0;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- CHECK_FSP(fsp,conn);
- CHECK_ERROR(fsp);
-
- mode = SVAL(inbuf,smb_vwv1) & 3;
- startpos = IVAL(inbuf,smb_vwv2);
-
- switch (mode & 3)
- {
- case 0: umode = SEEK_SET; break;
- case 1: umode = SEEK_CUR; break;
- case 2: umode = SEEK_END; break;
- default:
- umode = SEEK_SET; break;
- }
-
- if((res = conn->vfs_ops.lseek(fsp->fd_ptr->fd,startpos,umode)) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- fsp->pos = res;
-
- outsize = set_message(outbuf,2,0,True);
- SIVALS(outbuf,smb_vwv0,res);
-
- DEBUG(3,("lseek fnum=%d ofs=%.0f mode=%d\n",
- fsp->fnum, (double)startpos, mode));
-
- return(outsize);
-}
+ if (Protocol >= PROTOCOL_NT1)
+ {
+ uint16 flg2 = SVAL(outbuf, smb_flg2);
+ SSVAL(outbuf, smb_flg2, flg2 | 0x40); /* IS_LONG_NAME */
+ }
-/****************************************************************************
- reply to a flush
-****************************************************************************/
-int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = set_message(outbuf,0,0,True);
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- if (fsp) {
- CHECK_FSP(fsp,conn);
- CHECK_ERROR(fsp);
- }
-
- if (!fsp) {
- file_sync_all(conn);
- } else {
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
- }
-
- DEBUG(3,("flush\n"));
- return(outsize);
-}
+ outsize += DIR_STRUCT_SIZE * numentries;
+ smb_setlen(outbuf, outsize - 4);
+ if ((!*directory) && dptr_path(dptr_num))
+ slprintf(directory, sizeof(directory) - 1, "(%s)",
+ dptr_path(dptr_num));
-/****************************************************************************
- reply to a exit
-****************************************************************************/
-int reply_exit(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("exit\n"));
+ DEBUG(4, ("%s mask=%s path=%s dtype=%d nument=%d of %d\n",
+ smb_fn_name(CVAL(inbuf, smb_com)),
+ mask, directory, dirtype, numentries, maxentries));
- return(outsize);
+ return (outsize);
}
/****************************************************************************
- Reply to a close - has to deal with closing a directory opened by NT SMB's.
+ reply to a fclose (stop directory search)
****************************************************************************/
-int reply_close(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_fclose(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
int outsize = 0;
- time_t mtime;
- int32 eclass = 0, err = 0;
- files_struct *fsp = NULL;
-
- outsize = set_message(outbuf,0,0,True);
+ int status_len;
+ char *path;
+ char status[21];
+ int dptr_num = -1;
- /* If it's an IPC, pass off to the pipe handler. */
- if (IS_IPC(conn)) {
- return reply_pipe_close(conn, inbuf,outbuf);
- }
+ outsize = set_message(outbuf, 1, 0, True);
+ path = smb_buf(inbuf) + 1;
+ status_len = SVAL(smb_buf(inbuf), 3 + strlen(path));
- fsp = file_fsp(inbuf,smb_vwv0);
- /*
- * We can only use CHECK_FSP if we know it's not a directory.
- */
+ if (status_len == 0)
+ return (ERROR(ERRSRV, ERRsrverror));
- if(!fsp || !fsp->open || (fsp->conn != conn))
- return(ERROR(ERRDOS,ERRbadfid));
+ memcpy(status, smb_buf(inbuf) + 1 + strlen(path) + 4, 21);
- if(HAS_CACHED_ERROR(fsp)) {
- eclass = fsp->wbmpx_ptr->wr_errclass;
- err = fsp->wbmpx_ptr->wr_error;
+ if (dptr_fetch(status + 12, &dptr_num))
+ {
+ /* Close the dptr - we know it's gone */
+ dptr_close(dptr_num);
}
- if(fsp->is_directory) {
- /*
- * Special case - close NT SMB directory
- * handle.
- */
- DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
- close_directory(fsp);
- } else {
- /*
- * Close ordinary file.
- */
-
- /*
- * If there was a modify time outstanding,
- * try and set it here.
- */
- if(fsp->pending_modtime)
- set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
-
- /*
- * Now take care of any time sent in the close.
- */
- mtime = make_unix_date3(inbuf+smb_vwv1);
-
- /* try and set the date */
- set_filetime(conn, fsp->fsp_name,mtime);
-
- DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
- fsp->fd_ptr->fd, fsp->fnum,
- conn->num_files_open));
-
- close_file(fsp,True);
- }
+ SSVAL(outbuf, smb_vwv0, 0);
- /* We have a cached error */
- if(eclass || err)
- return(ERROR(eclass,err));
+ DEBUG(3, ("search close\n"));
- return(outsize);
+ return (outsize);
}
/****************************************************************************
- reply to a writeclose (Core+ protocol)
+ reply to an open
****************************************************************************/
-int reply_writeclose(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- size_t numtowrite;
- ssize_t nwritten = -1;
- int outsize = 0;
- SMB_OFF_T startpos;
- char *data;
- time_t mtime;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
- CHECK_ERROR(fsp);
-
- numtowrite = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- mtime = make_unix_date3(inbuf+smb_vwv4);
- data = smb_buf(inbuf) + 1;
-
- if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
- return(ERROR(ERRDOS,ERRlock));
-
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- nwritten = write_file(fsp,data,numtowrite);
-
- set_filetime(conn, fsp->fsp_name,mtime);
-
- close_file(fsp,True);
-
- DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
- fsp->fnum, numtowrite, nwritten,
- conn->num_files_open));
-
- if (nwritten <= 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- outsize = set_message(outbuf,1,0,True);
-
- SSVAL(outbuf,smb_vwv0,nwritten);
- return(outsize);
-}
-
-/****************************************************************************
- reply to a lock
-****************************************************************************/
-int reply_lock(connection_struct *conn,
- char *inbuf,char *outbuf, int length, int dum_buffsize)
+int reply_open(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- int outsize = set_message(outbuf,0,0,True);
- SMB_OFF_T count,offset;
- int eclass;
- uint32 ecode;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ pstring fname;
+ int outsize = 0;
+ int fmode = 0;
+ int share_mode;
+ SMB_OFF_T size = 0;
+ time_t mtime = 0;
+ mode_t unixmode;
+ int rmode = 0;
+ SMB_STRUCT_STAT sbuf;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
- CHECK_FSP(fsp,conn);
- CHECK_ERROR(fsp);
+ share_mode = SVAL(inbuf, smb_vwv0);
- count = IVAL(inbuf,smb_vwv1);
- offset = IVAL(inbuf,smb_vwv3);
-
- DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
- fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count));
-
- if (!do_lock(fsp, conn, count, offset, F_WRLCK, &eclass, &ecode)) {
- if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
- /*
- * A blocking lock was requested. Package up
- * this smb into a queued request and push it
- * onto the blocking lock queue.
- */
- if(push_blocking_lock_request(inbuf, length, -1, 0))
- return -1;
- }
- return (ERROR(eclass,ecode));
- }
-
- return(outsize);
-}
+ pstrcpy(fname, smb_buf(inbuf) + 1);
+ if (!unix_dfs_convert(fname, conn, 0, &bad_path, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+ fsp = file_new();
+ if (!fsp)
+ return (ERROR(ERRSRV, ERRnofids));
-/****************************************************************************
- reply to a unlock
-****************************************************************************/
-int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = set_message(outbuf,0,0,True);
- SMB_OFF_T count,offset;
- int eclass;
- uint32 ecode;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ if (!check_name(fname, conn))
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
- CHECK_FSP(fsp,conn);
- CHECK_ERROR(fsp);
+ unixmode = unix_mode(conn, aARCH);
- count = IVAL(inbuf,smb_vwv1);
- offset = IVAL(inbuf,smb_vwv3);
+ open_file_shared(fsp, conn, fname, share_mode,
+ (FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN),
+ unixmode, oplock_request, &rmode, NULL);
- if(!do_unlock(fsp, conn, count, offset, &eclass, &ecode))
- return (ERROR(eclass,ecode));
+ if (!fsp->open)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
- DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
- fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count ) );
-
- return(outsize);
-}
+ if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd, &sbuf) != 0)
+ {
+ close_file(fsp, False);
+ return (ERROR(ERRDOS, ERRnoaccess));
+ }
+ size = sbuf.st_size;
+ fmode = dos_mode(conn, fname, &sbuf);
+ mtime = sbuf.st_mtime;
-/****************************************************************************
- reply to a tdis
-****************************************************************************/
-int reply_tdis(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = set_message(outbuf,0,0,True);
- uint16 vuid;
+ if (fmode & aDIR)
+ {
+ DEBUG(3, ("attempt to open a directory %s\n", fname));
+ close_file(fsp, False);
+ return (ERROR(ERRDOS, ERRnoaccess));
+ }
- vuid = SVAL(inbuf,smb_uid);
+ outsize = set_message(outbuf, 7, 0, True);
+ SSVAL(outbuf, smb_vwv0, fsp->fnum);
+ SSVAL(outbuf, smb_vwv1, fmode);
+ if (lp_dos_filetime_resolution(SNUM(conn)))
+ put_dos_date3(outbuf, smb_vwv2, mtime & ~1);
+ else
+ put_dos_date3(outbuf, smb_vwv2, mtime);
+ SIVAL(outbuf, smb_vwv4, (uint32) size);
+ SSVAL(outbuf, smb_vwv6, rmode);
- if (!conn) {
- DEBUG(4,("Invalid connection in tdis\n"));
- return(ERROR(ERRSRV,ERRinvnid));
+ if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+ {
+ CVAL(outbuf, smb_flg) |= CORE_OPLOCK_GRANTED;
}
- conn->used = False;
-
- close_cnum(conn,vuid);
-
- return outsize;
+ if (fsp->granted_oplock)
+ CVAL(outbuf, smb_flg) |= CORE_OPLOCK_GRANTED;
+ return (outsize);
}
-
/****************************************************************************
- reply to a echo
+ reply to an open and X
****************************************************************************/
-int reply_echo(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_open_and_X(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
{
- int smb_reverb = SVAL(inbuf,smb_vwv0);
- int seq_num;
- int data_len = smb_buflen(inbuf);
- int outsize = set_message(outbuf,1,data_len,True);
-
- /* copy any incoming data back out */
- if (data_len > 0)
- memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
+ pstring fname;
+ int smb_mode = SVAL(inbuf, smb_vwv3);
+ int smb_attr = SVAL(inbuf, smb_vwv5);
+ /* Breakout the oplock request bits so we can set the
+ reply bits separately. */
+ BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+ BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+ BOOL oplock_request = ex_oplock_request | core_oplock_request;
+#if 0
+ int open_flags = SVAL(inbuf, smb_vwv2);
+ int smb_sattr = SVAL(inbuf, smb_vwv4);
+ uint32 smb_time = make_unix_date3(inbuf + smb_vwv6);
+#endif
+ int smb_ofun = SVAL(inbuf, smb_vwv8);
+ mode_t unixmode;
+ SMB_OFF_T size = 0;
+ int fmode = 0, mtime = 0, rmode = 0;
+ SMB_STRUCT_STAT sbuf;
+ int smb_action = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
- if (smb_reverb > 100) {
- DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
- smb_reverb = 100;
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn) && lp_nt_pipe_support()
+ && lp_security() != SEC_SHARE)
+ {
+ return reply_open_pipe_and_X(conn, inbuf, outbuf, length,
+ bufsize);
}
- for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
- SSVAL(outbuf,smb_vwv0,seq_num);
-
- smb_setlen(outbuf,outsize - 4);
+ /* XXXX we need to handle passed times, sattr and flags */
- send_smb(Client,outbuf);
+ pstrcpy(fname, smb_buf(inbuf));
+ if (!unix_dfs_convert(fname, conn, 0, &bad_path, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
}
- DEBUG(3,("echo %d times\n", smb_reverb));
+ fsp = file_new();
+ if (!fsp)
+ return (ERROR(ERRSRV, ERRnofids));
+
+ if (!check_name(fname, conn))
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ unixmode = unix_mode(conn, smb_attr | aARCH);
+
+ open_file_shared(fsp, conn, fname, smb_mode, smb_ofun, unixmode,
+ oplock_request, &rmode, &smb_action);
+
+ if (!fsp->open)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd, &sbuf) != 0)
+ {
+ close_file(fsp, False);
+ return (ERROR(ERRDOS, ERRnoaccess));
+ }
+
+ size = sbuf.st_size;
+ fmode = dos_mode(conn, fname, &sbuf);
+ mtime = sbuf.st_mtime;
+ if (fmode & aDIR)
+ {
+ close_file(fsp, False);
+ return (ERROR(ERRDOS, ERRnoaccess));
+ }
+
+ /* If the caller set the extended oplock request bit
+ and we granted one (by whatever means) - set the
+ correct bit for extended oplock reply.
+ */
+
+ if (ex_oplock_request && lp_fake_oplocks(SNUM(conn)))
+ {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ if (ex_oplock_request && fsp->granted_oplock)
+ {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
+ /* If the caller set the core oplock request bit
+ and we granted one (by whatever means) - set the
+ correct bit for core oplock reply.
+ */
+
+ if (core_oplock_request && lp_fake_oplocks(SNUM(conn)))
+ {
+ CVAL(outbuf, smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if (core_oplock_request && fsp->granted_oplock)
+ {
+ CVAL(outbuf, smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ set_message(outbuf, 15, 0, True);
+ SSVAL(outbuf, smb_vwv2, fsp->fnum);
+ SSVAL(outbuf, smb_vwv3, fmode);
+ if (lp_dos_filetime_resolution(SNUM(conn)))
+ put_dos_date3(outbuf, smb_vwv4, mtime & ~1);
+ else
+ put_dos_date3(outbuf, smb_vwv4, mtime);
+ SIVAL(outbuf, smb_vwv6, (uint32) size);
+ SSVAL(outbuf, smb_vwv8, rmode);
+ SSVAL(outbuf, smb_vwv11, smb_action);
+
+ return chain_reply(inbuf, outbuf, length, bufsize);
+}
+
+
+/****************************************************************************
+ reply to a SMBulogoffX
+****************************************************************************/
+int reply_ulogoffX(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
+{
+ uint16 vuid = SVAL(inbuf, smb_uid);
+ vuser_key key;
+ user_struct *vuser = NULL;
+ key.pid = conn != NULL ? conn->smbd_pid : getpid();
+ key.vuid = vuid;
+ vuser = get_valid_user_struct(&key);
+
+ if (vuser == 0)
+ {
+ DEBUG(3,
+ ("ulogoff, vuser id %d does not map to user.\n", vuid));
+ }
+
+ /* in user level security we are supposed to close any files
+ open by this user */
+ if ((vuser != 0) && (lp_security() != SEC_SHARE))
+ {
+ file_close_user(vuid);
+ }
+
+ invalidate_vuid(&key);
+
+ set_message(outbuf, 2, 0, True);
+
+ DEBUG(3, ("ulogoffX vuid=%d\n", vuid));
+
+ return chain_reply(inbuf, outbuf, length, bufsize);
+}
+
+
+/****************************************************************************
+ reply to a mknew or a create
+****************************************************************************/
+int reply_mknew(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ pstring fname;
+ int com;
+ int outsize = 0;
+ int createmode;
+ mode_t unixmode;
+ int ofun = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+
+ com = SVAL(inbuf, smb_com);
+
+ createmode = SVAL(inbuf, smb_vwv0);
+ pstrcpy(fname, smb_buf(inbuf) + 1);
+ if (!unix_dfs_convert(fname, conn, 0, &bad_path, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+
+ if (createmode & aVOLID)
+ {
+ DEBUG(0,
+ ("Attempt to create file (%s) with volid set - please report this\n",
+ fname));
+ }
+
+ unixmode = unix_mode(conn, createmode);
+
+ fsp = file_new();
+ if (!fsp)
+ return (ERROR(ERRSRV, ERRnofids));
+
+ if (!check_name(fname, conn))
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ if (com == SMBmknew)
+ {
+ /* We should fail if file exists. */
+ ofun = 0x10;
+ }
+ else
+ {
+ /* SMBcreate - Create if file doesn't exist, truncate if it does. */
+ ofun = 0x12;
+ }
+
+ /* Open file in dos compatibility share mode. */
+ open_file_shared(fsp, conn, fname,
+ SET_DENY_MODE(DENY_FCB) |
+ SET_OPEN_MODE(DOS_OPEN_FCB), ofun, unixmode,
+ oplock_request, NULL, NULL);
+
+ if (!fsp->open)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ outsize = set_message(outbuf, 1, 0, True);
+ SSVAL(outbuf, smb_vwv0, fsp->fnum);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+ {
+ CVAL(outbuf, smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if (fsp->granted_oplock)
+ CVAL(outbuf, smb_flg) |= CORE_OPLOCK_GRANTED;
+
+ DEBUG(2, ("new file %s\n", fname));
+ DEBUG(3, ("mknew %s fd=%d dmode=%d umode=%o\n",
+ fname, fsp->fd_ptr->fd, createmode, (int)unixmode));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a create temporary file
+****************************************************************************/
+int reply_ctemp(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ pstring fname;
+ pstring fname2;
+ int outsize = 0;
+ int createmode;
+ mode_t unixmode;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+
+ createmode = SVAL(inbuf, smb_vwv0);
+ pstrcpy(fname, smb_buf(inbuf) + 1);
+ pstrcat(fname, "/TMXXXXXX");
+ if (!unix_dfs_convert(fname, conn, 0, &bad_path, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+
+ unixmode = unix_mode(conn, createmode);
+
+ fsp = file_new();
+ if (fsp)
+ return (ERROR(ERRSRV, ERRnofids));
+
+ if (!check_name(fname, conn))
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ pstrcpy(fname2, (char *)mktemp(fname));
+
+ /* Open file in dos compatibility share mode. */
+ /* We should fail if file exists. */
+ open_file_shared(fsp, conn, fname2,
+ SET_DENY_MODE(DENY_FCB) |
+ SET_OPEN_MODE(DOS_OPEN_FCB),
+ (FILE_CREATE_IF_NOT_EXIST | FILE_EXISTS_FAIL),
+ unixmode, oplock_request, NULL, NULL);
+
+ if (!fsp->open)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ outsize = set_message(outbuf, 1, 2 + strlen(fname2), True);
+ SSVAL(outbuf, smb_vwv0, fsp->fnum);
+ CVAL(smb_buf(outbuf), 0) = 4;
+ pstrcpy(smb_buf(outbuf) + 1, fname2);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+ {
+ CVAL(outbuf, smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if (fsp->granted_oplock)
+ CVAL(outbuf, smb_flg) |= CORE_OPLOCK_GRANTED;
+
+ DEBUG(2, ("created temp file %s\n", fname2));
+ DEBUG(3, ("ctemp %s fd=%d dmode=%d umode=%o\n",
+ fname2, fsp->fd_ptr->fd, createmode, (int)unixmode));
+
+ return (outsize);
+}
+
+
+/*******************************************************************
+check if a user is allowed to delete a file
+********************************************************************/
+static BOOL can_delete(char *fname, connection_struct * conn, int dirtype)
+{
+ SMB_STRUCT_STAT sbuf;
+ int fmode;
+
+ if (!CAN_WRITE(conn))
+ return (False);
+
+ if (conn->vfs_ops.lstat(dos_to_unix(fname, False), &sbuf) != 0)
+ return (False);
+ fmode = dos_mode(conn, fname, &sbuf);
+ if (fmode & aDIR)
+ return (False);
+ if (!lp_delete_readonly(SNUM(conn)))
+ {
+ if (fmode & aRONLY)
+ return (False);
+ }
+ if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
+ return (False);
+ if (!check_file_sharing(conn, fname, False))
+ return (False);
+ return (True);
+}
+
+/****************************************************************************
+ reply to a unlink
+****************************************************************************/
+int reply_unlink(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ int outsize = 0;
+ pstring name;
+ int dirtype;
+ pstring directory;
+ pstring mask;
+ char *p;
+ int count = 0;
+ int error = ERRnoaccess;
+ BOOL has_wild;
+ BOOL exists = False;
+ BOOL bad_path = False;
+
+ *directory = *mask = 0;
+
+ dirtype = SVAL(inbuf, smb_vwv0);
+
+ pstrcpy(name, smb_buf(inbuf) + 1);
+
+ DEBUG(3, ("reply_unlink : %s\n", name));
+
+ if (!unix_dfs_convert(name, conn, 0, &bad_path, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+
+ p = strrchr(name, '/');
+ if (!p)
+ {
+ pstrcpy(directory, "./");
+ pstrcpy(mask, name);
+ }
+ else
+ {
+ *p = 0;
+ pstrcpy(directory, name);
+ pstrcpy(mask, p + 1);
+ }
+
+ if (is_mangled(mask))
+ check_mangled_cache(mask);
+
+ has_wild = strchr(mask, '*') || strchr(mask, '?');
+
+ if (!has_wild)
+ {
+ pstrcat(directory, "/");
+ pstrcat(directory, mask);
+ if (can_delete(directory, conn, dirtype) &&
+ !conn->vfs_ops.unlink(dos_to_unix(directory, False)))
+ count++;
+ if (!count)
+ exists =
+ vfs_file_exist(conn,
+ dos_to_unix(directory, False),
+ NULL);
+ }
+ else
+ {
+ void *dirptr = NULL;
+ char *dname;
+
+ if (check_name(directory, conn))
+ dirptr = OpenDir(conn, directory, True);
+
+ /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
+ the pattern matches against the long name, otherwise the short name
+ We don't implement this yet XXXX
+ */
+
+ if (dirptr)
+ {
+ error = ERRbadfile;
+
+ if (strequal(mask, "????????.???"))
+ pstrcpy(mask, "*");
+
+ while ((dname = ReadDirName(dirptr)))
+ {
+ pstring fname;
+ pstrcpy(fname, dname);
+
+ if (!mask_match
+ (fname, mask, case_sensitive,
+ False)) continue;
+
+ error = ERRnoaccess;
+ slprintf(fname, sizeof(fname) - 1, "%s/%s",
+ directory, dname);
+ if (!can_delete(fname, conn, dirtype))
+ continue;
+ if (!conn->vfs_ops.
+ unlink(dos_to_unix(fname, False)))
+ count++;
+ DEBUG(3,
+ ("reply_unlink : doing unlink on %s\n",
+ fname));
+ }
+ CloseDir(dirptr);
+ }
+ }
+
+ if (count == 0)
+ {
+ if (exists)
+ return (ERROR(ERRDOS, error));
+ else
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return (UNIXERROR(ERRDOS, error));
+ }
+ }
+
+ outsize = set_message(outbuf, 0, 0, True);
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a readbraw (core+ protocol)
+****************************************************************************/
+int reply_readbraw(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ size_t maxcount, mincount;
+ size_t nread = 0;
+ SMB_OFF_T startpos;
+ char *header = outbuf;
+ ssize_t ret = 0;
+ files_struct *fsp;
+
+ /*
+ * Special check if an oplock break has been issued
+ * and the readraw request croses on the wire, we must
+ * return a zero length response here.
+ */
+
+ if (global_oplock_break)
+ {
+ _smb_setlen(header, 0);
+ transfer_file(0, Client, (SMB_OFF_T) 0, header, 4, 0);
+ DEBUG(5, ("readbraw - oplock break finished\n"));
+ return -1;
+ }
+
+ fsp = file_fsp(inbuf, smb_vwv0);
+
+ startpos = IVAL(inbuf, smb_vwv1);
+#ifdef LARGE_SMB_OFF_T
+ if (CVAL(inbuf, smb_wct) == 10)
+ {
+ /*
+ * This is a large offset (64 bit) read.
+ */
+ startpos |= (((SMB_OFF_T) IVAL(inbuf, smb_vwv8)) << 32);
+ if (startpos < 0)
+ {
+ DEBUG(0,
+ ("readbraw - negative 64 bit readraw offset (%.0f) !\n",
+ (double)startpos));
+ _smb_setlen(header, 0);
+ transfer_file(0, Client, (SMB_OFF_T) 0, header, 4, 0);
+ return (-1);
+ }
+ }
+#endif /* LARGE_SMB_OFF_T */
+ maxcount = (SVAL(inbuf, smb_vwv3) & 0xFFFF);
+ mincount = (SVAL(inbuf, smb_vwv4) & 0xFFFF);
+
+ /* ensure we don't overrun the packet size */
+ maxcount = MIN(65535, maxcount);
+ maxcount = MAX(mincount, maxcount);
+
+ if (!FNUM_OK(fsp, conn) || !fsp->can_read)
+ {
+ DEBUG(3,
+ ("fnum %d not open in readbraw - cache prime?\n",
+ fsp->fnum));
+ _smb_setlen(header, 0);
+ transfer_file(0, Client, (SMB_OFF_T) 0, header, 4, 0);
+ return (-1);
+ }
+
+ if (!is_locked(fsp, conn, maxcount, startpos, F_RDLCK))
+ {
+ SMB_OFF_T size = fsp->size;
+ SMB_OFF_T sizeneeded = startpos + maxcount;
+
+ if (size < sizeneeded)
+ {
+ SMB_STRUCT_STAT st;
+ if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd, &st) ==
+ 0)
+ size = st.st_size;
+ if (!fsp->can_write)
+ fsp->size = size;
+ }
+
+ nread = MIN(maxcount, (size - startpos));
+ }
+
+ if (nread < mincount)
+ nread = 0;
+
+ DEBUG(3, ("readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
+ fsp->fnum, (double)startpos, maxcount, mincount, nread));
+
+#if UNSAFE_READRAW
+ {
+ BOOL seek_fail = False;
+ int predict = 0;
+ _smb_setlen(header, nread);
+
+#if USE_READ_PREDICTION
+ if (!fsp->can_write)
+ predict =
+ read_predict(fsp, fsp->fd_ptr->fd, startpos,
+ header + 4, NULL, nread);
+#endif /* USE_READ_PREDICTION */
+
+ if ((nread - predict) > 0)
+ {
+ if (conn->vfs_ops.seek(fsp, startpos + predict) == -1)
+ {
+ DEBUG(0,
+ ("reply_readbraw: ERROR: seek_file failed.\n"));
+ ret = 0;
+ seek_fail = True;
+ }
+ }
+
+ if (!seek_fail)
+ ret =
+ (ssize_t) vfs_transfer_file(-1,
+ fsp->fd_ptr->fd,
+ Client, NULL,
+ (SMB_OFF_T) (nread
+ -
+ predict),
+ header,
+ 4 + predict,
+ startpos +
+ predict);
+ }
+
+ if (ret != nread + 4)
+ DEBUG(0,
+ ("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
+ fsp->fsp_name, startpos, nread, ret));
+
+#else /* UNSAFE_READRAW */
+ ret = read_file(fsp, header + 4, startpos, nread);
+ if (ret < mincount)
+ ret = 0;
+
+ _smb_setlen(header, ret);
+ transfer_file(0, Client, 0, header, 4 + ret, 0);
+#endif /* UNSAFE_READRAW */
+
+ DEBUG(5, ("readbraw finished\n"));
+ return -1;
+}
+
+
+/****************************************************************************
+ reply to a lockread (core+ protocol)
+****************************************************************************/
+int reply_lockread(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int dum_buffsiz)
+{
+ ssize_t nread = -1;
+ char *data;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t numtoread;
+ int eclass;
+ uint32 ecode;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
+
+ numtoread = SVAL(inbuf, smb_vwv1);
+ startpos = IVAL(inbuf, smb_vwv2);
+
+ outsize = set_message(outbuf, 5, 3, True);
+ numtoread = MIN(BUFFER_SIZE - outsize, numtoread);
+ data = smb_buf(outbuf) + 3;
+
+ if (!do_lock
+ (fsp, conn, numtoread, startpos, F_RDLCK, &eclass, &ecode))
+ {
+ if ((ecode == ERRlock) && lp_blocking_locks(SNUM(conn)))
+ {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if (push_blocking_lock_request(inbuf, length, -1, 0))
+ return -1;
+ }
+ return (ERROR(eclass, ecode));
+ }
+
+ nread = read_file(fsp, data, startpos, numtoread);
+
+ if (nread < 0)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ outsize += nread;
+ SSVAL(outbuf, smb_vwv0, nread);
+ SSVAL(outbuf, smb_vwv5, nread + 3);
+ SSVAL(smb_buf(outbuf), 1, nread);
+
+ DEBUG(3, ("lockread fnum=%d num=%d nread=%d\n",
+ fsp->fnum, numtoread, nread));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a read
+****************************************************************************/
+int reply_read(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ size_t numtoread;
+ ssize_t nread = 0;
+ char *data;
+ SMB_OFF_T startpos;
+ int outsize = 0;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
+
+ numtoread = SVAL(inbuf, smb_vwv1);
+ startpos = IVAL(inbuf, smb_vwv2);
+
+ outsize = set_message(outbuf, 5, 3, True);
+ numtoread = MIN(BUFFER_SIZE - outsize, numtoread);
+ data = smb_buf(outbuf) + 3;
+
+ if (is_locked(fsp, conn, numtoread, startpos, F_RDLCK))
+ return (ERROR(ERRDOS, ERRlock));
+
+ if (numtoread > 0)
+ {
+ nread = read_file(fsp, data, startpos, numtoread);
+ }
+
+ if (nread < 0)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ outsize += nread;
+ SSVAL(outbuf, smb_vwv0, nread);
+ SSVAL(outbuf, smb_vwv5, nread + 3);
+ CVAL(smb_buf(outbuf), 0) = 1;
+ SSVAL(smb_buf(outbuf), 1, nread);
+
+ DEBUG(3, ("read fnum=%d num=%d nread=%d\n",
+ fsp->fnum, numtoread, nread));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a read and X
+****************************************************************************/
+int reply_read_and_X(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
+{
+ files_struct *fsp = file_fsp(inbuf, smb_vwv2);
+ SMB_OFF_T startpos = IVAL(inbuf, smb_vwv3);
+ size_t smb_maxcnt = SVAL(inbuf, smb_vwv5);
+ size_t smb_mincnt = SVAL(inbuf, smb_vwv6);
+ ssize_t nread = -1;
+ char *data;
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_pipe_read_and_X(inbuf, outbuf, length, bufsize);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
+
+ set_message(outbuf, 12, 0, True);
+ data = smb_buf(outbuf);
+
+#ifdef LARGE_SMB_OFF_T
+ if (CVAL(inbuf, smb_wct) == 12)
+ {
+ /*
+ * This is a large offset (64 bit) read.
+ */
+ startpos |= (((SMB_OFF_T) IVAL(inbuf, smb_vwv10)) << 32);
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ if (is_locked(fsp, conn, smb_maxcnt, startpos, F_RDLCK))
+ return (ERROR(ERRDOS, ERRlock));
+ nread = read_file(fsp, data, startpos, smb_maxcnt);
+
+ if (nread < 0)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ SSVAL(outbuf, smb_vwv5, nread);
+ SSVAL(outbuf, smb_vwv6, smb_offset(data, outbuf));
+ SSVAL(smb_buf(outbuf), -2, nread);
+
+ DEBUG(3, ("readX fnum=%d min=%d max=%d nread=%d\n",
+ fsp->fnum, smb_mincnt, smb_maxcnt, nread));
+
+ return chain_reply(inbuf, outbuf, length, bufsize);
+}
+
+/****************************************************************************
+ reply to a writebraw (core+ or LANMAN1.0 protocol)
+****************************************************************************/
+int reply_writebraw(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ ssize_t nwritten = 0;
+ ssize_t total_written = 0;
+ size_t numtowrite = 0;
+ size_t tcount;
+ SMB_OFF_T startpos;
+ char *data = NULL;
+ BOOL write_through;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+ int outsize = 0;
+
+ CHECK_FSP(fsp, conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ tcount = IVAL(inbuf, smb_vwv1);
+ startpos = IVAL(inbuf, smb_vwv3);
+ write_through = BITSETW(inbuf + smb_vwv7, 0);
+
+ /* We have to deal with slightly different formats depending
+ on whether we are using the core+ or lanman1.0 protocol */
+ if (Protocol <= PROTOCOL_COREPLUS)
+ {
+ numtowrite = SVAL(smb_buf(inbuf), -2);
+ data = smb_buf(inbuf);
+ }
+ else
+ {
+ numtowrite = SVAL(inbuf, smb_vwv10);
+ data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
+ }
+
+ /* force the error type */
+ CVAL(inbuf, smb_com) = SMBwritec;
+ CVAL(outbuf, smb_com) = SMBwritec;
+
+ if (is_locked(fsp, conn, tcount, startpos, F_WRLCK))
+ return (ERROR(ERRDOS, ERRlock));
+
+ if (seek_file(fsp, startpos) == -1)
+ {
+ DEBUG(0,
+ ("couldn't seek to %.0f in writebraw\n",
+ (double)startpos));
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ if (numtowrite > 0)
+ nwritten = write_file(fsp, data, numtowrite);
+
+ DEBUG(3, ("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
+ fsp->fnum, (double)startpos, numtowrite, nwritten,
+ write_through));
+
+ if (nwritten < numtowrite)
+ return (UNIXERROR(ERRHRD, ERRdiskfull));
+
+ total_written = nwritten;
+
+ /* Return a message to the redirector to tell it
+ to send more bytes */
+ CVAL(outbuf, smb_com) = SMBwritebraw;
+ SSVALS(outbuf, smb_vwv0, -1);
+ outsize =
+ set_message(outbuf, Protocol > PROTOCOL_COREPLUS ? 1 : 0, 0,
+ True);
+ send_smb(Client, outbuf);
+
+ /* Now read the raw data into the buffer and write it */
+ if (read_smb_length(Client, inbuf, SMB_SECONDARY_WAIT) == -1)
+ {
+ exit_server("secondary writebraw failed");
+ }
+
+ /* Even though this is not an smb message, smb_len
+ returns the generic length of an smb message */
+ numtowrite = smb_len(inbuf);
+
+ if (tcount > nwritten + numtowrite)
+ {
+ DEBUG(3, ("Client overestimated the write %d %d %d\n",
+ tcount, nwritten, numtowrite));
+ }
+
+ nwritten = vfs_transfer_file(Client, NULL, -1, fsp,
+ (SMB_OFF_T) numtowrite, NULL, 0,
+ startpos + nwritten);
+ total_written += nwritten;
+
+ /* Set up outbuf to return the correct return */
+ outsize = set_message(outbuf, 1, 0, True);
+ CVAL(outbuf, smb_com) = SMBwritec;
+ SSVAL(outbuf, smb_vwv0, total_written);
+
+ if (nwritten < (ssize_t) numtowrite)
+ {
+ CVAL(outbuf, smb_rcls) = ERRHRD;
+ SSVAL(outbuf, smb_err, ERRdiskfull);
+ }
+
+ if ((lp_syncalways(SNUM(conn)) || write_through) &&
+ lp_strict_sync(SNUM(conn)))
+ conn->vfs_ops.sync(fsp->fd_ptr->fd);
+
+ DEBUG(3, ("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
+ fsp->fnum, (double)startpos, numtowrite, total_written));
+
+ /* we won't return a status if write through is not selected - this
+ follows what WfWg does */
+ if (!write_through && total_written == tcount)
+ return (-1);
+
+ return (outsize);
+}
+
+/****************************************************************************
+ reply to a writeunlock (core+)
+****************************************************************************/
+int reply_writeunlock(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ ssize_t nwritten = -1;
+ size_t numtowrite;
+ SMB_OFF_T startpos;
+ char *data;
+ int eclass;
+ uint32 ecode;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+ int outsize = 0;
+
+ CHECK_FSP(fsp, conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ numtowrite = SVAL(inbuf, smb_vwv1);
+ startpos = IVAL(inbuf, smb_vwv2);
+ data = smb_buf(inbuf) + 3;
+
+ if (is_locked(fsp, conn, numtowrite, startpos, F_WRLCK))
+ return (ERROR(ERRDOS, ERRlock));
+
+ if (seek_file(fsp, startpos) == -1)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ /* The special X/Open SMB protocol handling of
+ zero length writes is *NOT* done for
+ this call */
+ if (numtowrite == 0)
+ nwritten = 0;
+ else
+ nwritten = write_file(fsp, data, numtowrite);
+
+ if (lp_syncalways(SNUM(conn)) && lp_strict_sync(SNUM(conn)))
+ conn->vfs_ops.sync(fsp->fd_ptr->fd);
+
+ if (((nwritten == 0) && (numtowrite != 0)) || (nwritten < 0))
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ if (!do_unlock(fsp, conn, numtowrite, startpos, &eclass, &ecode))
+ return (ERROR(eclass, ecode));
+
+ outsize = set_message(outbuf, 1, 0, True);
+
+ SSVAL(outbuf, smb_vwv0, nwritten);
+
+ DEBUG(3, ("writeunlock fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, numtowrite, nwritten));
+
+ return (outsize);
+}
+
+/****************************************************************************
+ reply to a write
+****************************************************************************/
+int reply_write(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ SMB_OFF_T startpos;
+ char *data;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+ int outsize = 0;
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_pipe_write(inbuf, outbuf, dum_size,
+ dum_buffsize);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ numtowrite = SVAL(inbuf, smb_vwv1);
+ startpos = IVAL(inbuf, smb_vwv2);
+ data = smb_buf(inbuf) + 3;
+
+ if (is_locked(fsp, conn, numtowrite, startpos, F_WRLCK))
+ return (ERROR(ERRDOS, ERRlock));
+
+ if (seek_file(fsp, startpos) == -1)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ /* X/Open SMB protocol says that if smb_vwv1 is
+ zero then the file size should be extended or
+ truncated to the size given in smb_vwv[2-3] */
+ if (numtowrite == 0)
+ nwritten = set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T) startpos);
+ else
+ nwritten = write_file(fsp, data, numtowrite);
+
+ if (lp_syncalways(SNUM(conn)) && lp_strict_sync(SNUM(conn)))
+ conn->vfs_ops.sync(fsp->fd_ptr->fd);
+
+ if (((nwritten == 0) && (numtowrite != 0)) || (nwritten < 0))
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ outsize = set_message(outbuf, 1, 0, True);
+
+ SSVAL(outbuf, smb_vwv0, nwritten);
+
+ if (nwritten < (ssize_t) numtowrite)
+ {
+ CVAL(outbuf, smb_rcls) = ERRHRD;
+ SSVAL(outbuf, smb_err, ERRdiskfull);
+ }
+
+ DEBUG(3, ("write fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, numtowrite, nwritten));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a write and X
+****************************************************************************/
+int reply_write_and_X(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
+{
+ files_struct *fsp = file_fsp(inbuf, smb_vwv2);
+ SMB_OFF_T startpos = IVAL(inbuf, smb_vwv3);
+ size_t numtowrite = SVAL(inbuf, smb_vwv10);
+ BOOL write_through = BITSETW(inbuf + smb_vwv7, 0);
+ ssize_t nwritten = -1;
+ int smb_doff = SVAL(inbuf, smb_vwv11);
+ char *data;
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_pipe_write_and_X(inbuf, outbuf, length, bufsize);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ data = smb_base(inbuf) + smb_doff;
+
+#ifdef LARGE_SMB_OFF_T
+ if (CVAL(inbuf, smb_wct) == 14)
+ {
+ /*
+ * This is a large offset (64 bit) write.
+ */
+ startpos |= (((SMB_OFF_T) IVAL(inbuf, smb_vwv12)) << 32);
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ if (is_locked(fsp, conn, numtowrite, startpos, F_WRLCK))
+ return (ERROR(ERRDOS, ERRlock));
+
+ if (seek_file(fsp, startpos) == -1)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ /* X/Open SMB protocol says that, unlike SMBwrite
+ if the length is zero then NO truncation is
+ done, just a write of zero. To truncate a file,
+ use SMBwrite. */
+ if (numtowrite == 0)
+ nwritten = 0;
+ else
+ nwritten = write_file(fsp, data, numtowrite);
+
+ if (((nwritten == 0) && (numtowrite != 0)) || (nwritten < 0))
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ set_message(outbuf, 6, 0, True);
+
+ SSVAL(outbuf, smb_vwv2, nwritten);
+
+ if (nwritten < (ssize_t) numtowrite)
+ {
+ CVAL(outbuf, smb_rcls) = ERRHRD;
+ SSVAL(outbuf, smb_err, ERRdiskfull);
+ }
+
+ DEBUG(3, ("writeX fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, numtowrite, nwritten));
+
+ if ((lp_syncalways(SNUM(conn)) || write_through) &&
+ lp_strict_sync(SNUM(conn)))
+ conn->vfs_ops.sync(fsp->fd_ptr->fd);
+
+ return chain_reply(inbuf, outbuf, length, bufsize);
+}
+
+
+/****************************************************************************
+ reply to a lseek
+****************************************************************************/
+int reply_lseek(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ SMB_OFF_T startpos;
+ SMB_OFF_T res = -1;
+ int mode, umode;
+ int outsize = 0;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_ERROR(fsp);
+
+ mode = SVAL(inbuf, smb_vwv1) & 3;
+ startpos = IVAL(inbuf, smb_vwv2);
+
+ switch (mode & 3)
+ {
+ case 0:
+ umode = SEEK_SET;
+ break;
+ case 1:
+ umode = SEEK_CUR;
+ break;
+ case 2:
+ umode = SEEK_END;
+ break;
+ default:
+ umode = SEEK_SET;
+ break;
+ }
+
+ if ((res = conn->vfs_ops.lseek(fsp->fd_ptr->fd, startpos, umode)) ==
+ -1)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ fsp->pos = res;
+
+ outsize = set_message(outbuf, 2, 0, True);
+ SIVALS(outbuf, smb_vwv0, res);
+
+ DEBUG(3, ("lseek fnum=%d ofs=%.0f mode=%d\n",
+ fsp->fnum, (double)startpos, mode));
+
+ return (outsize);
+}
+
+/****************************************************************************
+ reply to a flush
+****************************************************************************/
+int reply_flush(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ int outsize = set_message(outbuf, 0, 0, True);
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ if (fsp)
+ {
+ CHECK_FSP(fsp, conn);
+ CHECK_ERROR(fsp);
+ }
+
+ if (!fsp)
+ {
+ file_sync_all(conn);
+ }
+ else
+ {
+ conn->vfs_ops.sync(fsp->fd_ptr->fd);
+ }
+
+ DEBUG(3, ("flush\n"));
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a exit
+****************************************************************************/
+int reply_exit(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
+{
+ int outsize = set_message(outbuf, 0, 0, True);
+ DEBUG(3, ("exit\n"));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ Reply to a close - has to deal with closing a directory opened by NT SMB's.
+****************************************************************************/
+int reply_close(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
+{
+ int outsize = 0;
+ time_t mtime;
+ int32 eclass = 0, err = 0;
+ files_struct *fsp = NULL;
+
+ outsize = set_message(outbuf, 0, 0, True);
+
+ /* If it's an IPC, pass off to the pipe handler. */
+ if (IS_IPC(conn))
+ {
+ return reply_pipe_close(conn, inbuf, outbuf);
+ }
+
+ fsp = file_fsp(inbuf, smb_vwv0);
+
+ /*
+ * We can only use CHECK_FSP if we know it's not a directory.
+ */
+
+ if (!fsp || !fsp->open || (fsp->conn != conn))
+ return (ERROR(ERRDOS, ERRbadfid));
+
+ if (HAS_CACHED_ERROR(fsp))
+ {
+ eclass = fsp->wbmpx_ptr->wr_errclass;
+ err = fsp->wbmpx_ptr->wr_error;
+ }
+
+ if (fsp->is_directory)
+ {
+ /*
+ * Special case - close NT SMB directory
+ * handle.
+ */
+ DEBUG(3, ("close directory fnum=%d\n", fsp->fnum));
+ close_directory(fsp);
+ }
+ else
+ {
+ /*
+ * Close ordinary file.
+ */
+
+ /*
+ * If there was a modify time outstanding,
+ * try and set it here.
+ */
+ if (fsp->pending_modtime)
+ set_filetime(conn, fsp->fsp_name,
+ fsp->pending_modtime);
+
+ /*
+ * Now take care of any time sent in the close.
+ */
+ mtime = make_unix_date3(inbuf + smb_vwv1);
+
+ /* try and set the date */
+ set_filetime(conn, fsp->fsp_name, mtime);
+
+ DEBUG(3, ("close fd=%d fnum=%d (numopen=%d)\n",
+ fsp->fd_ptr->fd, fsp->fnum, conn->num_files_open));
+
+ close_file(fsp, True);
+ }
+
+ /* We have a cached error */
+ if (eclass || err)
+ return (ERROR(eclass, err));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a writeclose (Core+ protocol)
+****************************************************************************/
+int reply_writeclose(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size,
+ int dum_buffsize)
+{
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ char *data;
+ time_t mtime;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ numtowrite = SVAL(inbuf, smb_vwv1);
+ startpos = IVAL(inbuf, smb_vwv2);
+ mtime = make_unix_date3(inbuf + smb_vwv4);
+ data = smb_buf(inbuf) + 1;
+
+ if (is_locked(fsp, conn, numtowrite, startpos, F_WRLCK))
+ return (ERROR(ERRDOS, ERRlock));
+
+ if (seek_file(fsp, startpos) == -1)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ nwritten = write_file(fsp, data, numtowrite);
+
+ set_filetime(conn, fsp->fsp_name, mtime);
+
+ close_file(fsp, True);
+
+ DEBUG(3, ("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
+ fsp->fnum, numtowrite, nwritten, conn->num_files_open));
+
+ if (nwritten <= 0)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ outsize = set_message(outbuf, 1, 0, True);
+
+ SSVAL(outbuf, smb_vwv0, nwritten);
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a lock
+****************************************************************************/
+int reply_lock(connection_struct * conn,
+ char *inbuf, char *outbuf, int length, int dum_buffsize)
+{
+ int outsize = set_message(outbuf, 0, 0, True);
+ SMB_OFF_T count, offset;
+ int eclass;
+ uint32 ecode;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_ERROR(fsp);
+
+ count = IVAL(inbuf, smb_vwv1);
+ offset = IVAL(inbuf, smb_vwv3);
+
+ DEBUG(3, ("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count));
+
+ if (!do_lock(fsp, conn, count, offset, F_WRLCK, &eclass, &ecode))
+ {
+ if ((ecode == ERRlock) && lp_blocking_locks(SNUM(conn)))
+ {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if (push_blocking_lock_request(inbuf, length, -1, 0))
+ return -1;
+ }
+ return (ERROR(eclass, ecode));
+ }
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a unlock
+****************************************************************************/
+int reply_unlock(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ int outsize = set_message(outbuf, 0, 0, True);
+ SMB_OFF_T count, offset;
+ int eclass;
+ uint32 ecode;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_ERROR(fsp);
+
+ count = IVAL(inbuf, smb_vwv1);
+ offset = IVAL(inbuf, smb_vwv3);
+
+ if (!do_unlock(fsp, conn, count, offset, &eclass, &ecode))
+ return (ERROR(eclass, ecode));
+
+ DEBUG(3, ("unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a tdis
+****************************************************************************/
+int reply_tdis(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
+{
+ int outsize = set_message(outbuf, 0, 0, True);
+ uint16 vuid;
+
+ vuid = SVAL(inbuf, smb_uid);
+
+ if (!conn)
+ {
+ DEBUG(4, ("Invalid connection in tdis\n"));
+ return (ERROR(ERRSRV, ERRinvnid));
+ }
+
+ conn->used = False;
+
+ close_cnum(conn, vuid);
+
+ return outsize;
+}
+
+
+
+/****************************************************************************
+ reply to a echo
+****************************************************************************/
+int reply_echo(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
+{
+ int smb_reverb = SVAL(inbuf, smb_vwv0);
+ int seq_num;
+ int data_len = smb_buflen(inbuf);
+ int outsize = set_message(outbuf, 1, data_len, True);
+
+ /* copy any incoming data back out */
+ if (data_len > 0)
+ memcpy(smb_buf(outbuf), smb_buf(inbuf), data_len);
+
+ if (smb_reverb > 100)
+ {
+ DEBUG(0,
+ ("large reverb (%d)?? Setting to 100\n", smb_reverb));
+ smb_reverb = 100;
+ }
+
+ for (seq_num = 1; seq_num <= smb_reverb; seq_num++)
+ {
+ SSVAL(outbuf, smb_vwv0, seq_num);
+
+ smb_setlen(outbuf, outsize - 4);
+
+ send_smb(Client, outbuf);
+ }
+
+ DEBUG(3, ("echo %d times\n", smb_reverb));
return -1;
}
/****************************************************************************
reply to a printopen
****************************************************************************/
-int reply_printopen(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_printopen(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
{
pstring fname;
pstring fname2;
int outsize = 0;
files_struct *fsp;
-
+
*fname = *fname2 = 0;
-
+
if (!CAN_PRINT(conn))
- return(ERROR(ERRDOS,ERRnoaccess));
+ return (ERROR(ERRDOS, ERRnoaccess));
{
pstring s;
char *p;
- pstrcpy(s,smb_buf(inbuf)+1);
+ pstrcpy(s, smb_buf(inbuf) + 1);
p = s;
- while (*p) {
- if (!(isalnum((int)*p) || strchr("._-",*p)))
+ while (*p)
+ {
+ if (!(isalnum((int)*p) || strchr("._-", *p)))
*p = 'X';
p++;
}
- if (strlen(s) > 10) s[10] = 0;
+ if (strlen(s) > 10)
+ s[10] = 0;
- slprintf(fname,sizeof(fname)-1, "%s.XXXXXX",s);
+ slprintf(fname, sizeof(fname) - 1, "%s.XXXXXX", s);
}
fsp = file_new();
if (!fsp)
- return(ERROR(ERRSRV,ERRnofids));
-
- pstrcpy(fname2,(char *)mktemp(fname));
+ return (ERROR(ERRSRV, ERRnofids));
+
+ pstrcpy(fname2, (char *)mktemp(fname));
+
+ if (!check_name(fname2, conn))
+ {
+ file_free(fsp);
+ return (ERROR(ERRDOS, ERRnoaccess));
+ }
+
+ /* Open for exclusive use, write only. */
+ open_file_shared(fsp, conn, fname2,
+ SET_DENY_MODE(DENY_ALL) |
+ SET_OPEN_MODE(DOS_OPEN_WRONLY),
+ (FILE_CREATE_IF_NOT_EXIST | FILE_EXISTS_FAIL),
+ unix_mode(conn, 0), 0, NULL, NULL);
+
+ if (!fsp->open)
+ {
+ file_free(fsp);
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ /* force it to be a print file */
+ fsp->print_file = True;
+
+ outsize = set_message(outbuf, 1, 0, True);
+ SSVAL(outbuf, smb_vwv0, fsp->fnum);
+
+ DEBUG(3, ("openprint %s fd=%d fnum=%d\n",
+ fname2, fsp->fd_ptr->fd, fsp->fnum));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a printclose
+****************************************************************************/
+int reply_printclose(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size,
+ int dum_buffsize)
+{
+ int outsize = set_message(outbuf, 0, 0, True);
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_ERROR(fsp);
+
+ if (!CAN_PRINT(conn))
+ return (ERROR(ERRDOS, ERRnoaccess));
+
+ DEBUG(3, ("printclose fd=%d fnum=%d\n", fsp->fd_ptr->fd, fsp->fnum));
+
+ close_file(fsp, True);
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a printqueue
+****************************************************************************/
+int reply_printqueue(connection_struct * conn,
+ char *inbuf, char *outbuf, int dum_size,
+ int dum_buffsize)
+{
+ int outsize = set_message(outbuf, 2, 3, True);
+ int max_count = SVAL(inbuf, smb_vwv0);
+ int start_index = SVAL(inbuf, smb_vwv1);
+ uint16 vuid = SVAL(inbuf, smb_uid);
+ VUSER_KEY;
+
+ /* we used to allow the client to get the cnum wrong, but that
+ is really quite gross and only worked when there was only
+ one printer - I think we should now only accept it if they
+ get it right (tridge) */
+ if (!CAN_PRINT(conn))
+ return (ERROR(ERRDOS, ERRnoaccess));
+
+ SSVAL(outbuf, smb_vwv0, 0);
+ SSVAL(outbuf, smb_vwv1, 0);
+ CVAL(smb_buf(outbuf), 0) = 1;
+ SSVAL(smb_buf(outbuf), 1, 0);
+
+ DEBUG(3, ("printqueue start_index=%d max_count=%d\n",
+ start_index, max_count));
+
+ {
+ print_queue_struct *queue = NULL;
+ char *p = smb_buf(outbuf) + 3;
+ int count =
+ get_printqueue(SNUM(conn), conn, &key, &queue, NULL);
+ int num_to_get = ABS(max_count);
+ int first =
+ (max_count >
+ 0 ? start_index : start_index + max_count + 1);
+ int i;
+
+ if (first >= count)
+ num_to_get = 0;
+ else
+ num_to_get = MIN(num_to_get, count - first);
+
+
+ for (i = first; i < first + num_to_get; i++)
+ {
+ put_dos_date2(p, 0, queue[i].time);
+ CVAL(p, 4) =
+ (queue[i].status == LPQ_PRINTING ? 2 : 3);
+ SSVAL(p, 5,
+ printjob_encode(SNUM(conn), queue[i].job));
+ SIVAL(p, 7, queue[i].size);
+ CVAL(p, 11) = 0;
+ StrnCpy(p + 12, queue[i].user, 16);
+ p += 28;
+ }
+
+ if (count > 0)
+ {
+ outsize =
+ set_message(outbuf, 2, 28 * count + 3, False);
+ SSVAL(outbuf, smb_vwv0, count);
+ SSVAL(outbuf, smb_vwv1,
+ (max_count > 0 ? first + count : first - 1));
+ CVAL(smb_buf(outbuf), 0) = 1;
+ SSVAL(smb_buf(outbuf), 1, 28 * count);
+ }
+
+ if (queue)
+ free(queue);
+
+ DEBUG(3, ("%d entries returned in queue\n", count));
+ }
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a printwrite
+****************************************************************************/
+int reply_printwrite(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ int numtowrite;
+ int outsize = set_message(outbuf, 0, 0, True);
+ char *data;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ if (!CAN_PRINT(conn))
+ return (ERROR(ERRDOS, ERRnoaccess));
+
+ CHECK_FSP(fsp, conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ numtowrite = SVAL(smb_buf(inbuf), 1);
+ data = smb_buf(inbuf) + 3;
+
+ if (write_file(fsp, data, numtowrite) != numtowrite)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ DEBUG(3, ("printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite));
+
+ return (outsize);
+}
+
+
+/****************************************************************************
+ reply to a mkdir
+****************************************************************************/
+int reply_mkdir(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ pstring directory;
+ int outsize, ret = -1;
+ BOOL bad_path = False;
+
+ pstrcpy(directory, smb_buf(inbuf) + 1);
+ if (!unix_dfs_convert(directory, conn, 0, &bad_path, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+
+ if (check_name(directory, conn))
+ ret = conn->vfs_ops.mkdir(dos_to_unix(directory, False),
+ unix_mode(conn, aDIR));
+
+ if (ret < 0)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+
+ outsize = set_message(outbuf, 0, 0, True);
+
+ DEBUG(3, ("mkdir %s ret=%d\n", directory, ret));
+
+ return (outsize);
+}
+
+/****************************************************************************
+Static function used by reply_rmdir to delete an entire directory
+tree recursively.
+****************************************************************************/
+static BOOL recursive_rmdir(connection_struct * conn, char *directory)
+{
+ char *dname = NULL;
+ BOOL ret = False;
+ void *dirptr = OpenDir(conn, directory, False);
+
+ if (dirptr == NULL)
+ return True;
+
+ while ((dname = ReadDirName(dirptr)))
+ {
+ pstring fullname;
+ SMB_STRUCT_STAT st;
+
+ if ((strcmp(dname, ".") == 0) || (strcmp(dname, "..") == 0))
+ continue;
+
+ /* Construct the full name. */
+ if (strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
+ {
+ errno = ENOMEM;
+ ret = True;
+ break;
+ }
+ pstrcpy(fullname, directory);
+ pstrcat(fullname, "/");
+ pstrcat(fullname, dname);
+
+ if (conn->vfs_ops.lstat(dos_to_unix(fullname, False), &st) !=
+ 0)
+ {
+ ret = True;
+ break;
+ }
+
+ if (st.st_mode & S_IFDIR)
+ {
+ if (recursive_rmdir(conn, fullname) != 0)
+ {
+ ret = True;
+ break;
+ }
+ if (conn->vfs_ops.
+ rmdir(dos_to_unix(fullname, False)) != 0)
+ {
+ ret = True;
+ break;
+ }
+ }
+ else if (conn->vfs_ops.unlink(dos_to_unix(fullname, False)) !=
+ 0)
+ {
+ ret = True;
+ break;
+ }
+ }
+ CloseDir(dirptr);
+ return ret;
+}
+
+/****************************************************************************
+ reply to a rmdir
+****************************************************************************/
+int reply_rmdir(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ pstring directory;
+ int outsize = 0;
+ BOOL ok = False;
+ BOOL bad_path = False;
+
+ pstrcpy(directory, smb_buf(inbuf) + 1);
+ if (!unix_dfs_convert(directory, conn, NULL, &bad_path, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+
+ if (check_name(directory, conn))
+ {
+
+ dptr_closepath(directory, SVAL(inbuf, smb_pid));
+ ok =
+ (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) ==
+ 0);
+ if (!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(conn)))
+ {
+ /* Check to see if the only thing in this directory are
+ vetoed files/directories. If so then delete them and
+ retry. If we fail to delete any of them (and we *don't*
+ do a recursive delete) then fail the rmdir. */
+ BOOL all_veto_files = True;
+ char *dname;
+ void *dirptr = OpenDir(conn, directory, False);
+
+ if (dirptr != NULL)
+ {
+ int dirpos = TellDir(dirptr);
+ while ((dname = ReadDirName(dirptr)))
+ {
+ if ((strcmp(dname, ".") == 0)
+ || (strcmp(dname, "..") == 0))
+ continue;
+ if (!IS_VETO_PATH(conn, dname))
+ {
+ all_veto_files = False;
+ break;
+ }
+ }
+ if (all_veto_files)
+ {
+ SeekDir(dirptr, dirpos);
+ while ((dname = ReadDirName(dirptr)))
+ {
+ pstring fullname;
+ SMB_STRUCT_STAT st;
+
+ if ((strcmp(dname, ".") == 0)
+ || (strcmp(dname, "..") ==
+ 0))
+ continue;
+
+ /* Construct the full name. */
+ if (strlen(directory) +
+ strlen(dname) + 1 >=
+ sizeof(fullname))
+ {
+ errno = ENOMEM;
+ break;
+ }
+ pstrcpy(fullname, directory);
+ pstrcat(fullname, "/");
+ pstrcat(fullname, dname);
+
+ if (conn->vfs_ops.
+ lstat(dos_to_unix
+ (fullname, False),
+ &st) != 0)
+ break;
+ if (st.st_mode & S_IFDIR)
+ {
+ if
+ (lp_recursive_veto_delete
+ (SNUM(conn)))
+ {
+ DEBUG(0,
+ ("ERROR: recursive_rmdir()\n"));
+ if
+ (recursive_rmdir
+ (conn,
+ fullname)
+ != 0)
+ break;
+ }
+ if (conn->vfs_ops.
+ rmdir(dos_to_unix
+ (fullname,
+ False)) !=
+ 0)
+ break;
+ }
+ else if (conn->vfs_ops.
+ unlink(dos_to_unix
+ (fullname,
+ False)) != 0)
+ break;
+ }
+ CloseDir(dirptr);
+ /* Retry the rmdir */
+ ok =
+ (conn->vfs_ops.
+ rmdir(dos_to_unix
+ (directory, False)) == 0);
+ }
+ else
+ CloseDir(dirptr);
+ }
+ else
+ errno = ENOTEMPTY;
+ }
- if (!check_name(fname2,conn)) {
- file_free(fsp);
- return(ERROR(ERRDOS,ERRnoaccess));
+ if (!ok)
+ DEBUG(3, ("couldn't remove directory %s : %s\n",
+ directory, strerror(errno)));
}
- /* Open for exclusive use, write only. */
- open_file_shared(fsp,conn,fname2, SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
- (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unix_mode(conn,0), 0, NULL, NULL);
-
- if (!fsp->open) {
- file_free(fsp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if (!ok)
+ {
+ if ((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return (UNIXERROR(ERRDOS, ERRbadpath));
}
- /* force it to be a print file */
- fsp->print_file = True;
-
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,fsp->fnum);
-
- DEBUG(3,("openprint %s fd=%d fnum=%d\n",
- fname2, fsp->fd_ptr->fd, fsp->fnum));
-
- return(outsize);
-}
-
-
-/****************************************************************************
- reply to a printclose
-****************************************************************************/
-int reply_printclose(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = set_message(outbuf,0,0,True);
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ outsize = set_message(outbuf, 0, 0, True);
- CHECK_FSP(fsp,conn);
- CHECK_ERROR(fsp);
+ DEBUG(3, ("rmdir %s\n", directory));
- if (!CAN_PRINT(conn))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- DEBUG(3,("printclose fd=%d fnum=%d\n",
- fsp->fd_ptr->fd,fsp->fnum));
-
- close_file(fsp,True);
-
- return(outsize);
+ return (outsize);
}
-/****************************************************************************
- reply to a printqueue
-****************************************************************************/
-int reply_printqueue(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+/*******************************************************************
+resolve wildcards in a filename rename
+********************************************************************/
+static BOOL resolve_wildcards(char *name1, char *name2)
{
- int outsize = set_message(outbuf,2,3,True);
- int max_count = SVAL(inbuf,smb_vwv0);
- int start_index = SVAL(inbuf,smb_vwv1);
- uint16 vuid = SVAL(inbuf,smb_uid);
- VUSER_KEY;
+ fstring root1, root2;
+ fstring ext1, ext2;
+ char *p, *p2;
- /* we used to allow the client to get the cnum wrong, but that
- is really quite gross and only worked when there was only
- one printer - I think we should now only accept it if they
- get it right (tridge) */
- if (!CAN_PRINT(conn))
- return(ERROR(ERRDOS,ERRnoaccess));
+ name1 = strrchr(name1, '/');
+ name2 = strrchr(name2, '/');
- SSVAL(outbuf,smb_vwv0,0);
- SSVAL(outbuf,smb_vwv1,0);
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,0);
-
- DEBUG(3,("printqueue start_index=%d max_count=%d\n",
- start_index, max_count));
+ if (!name1 || !name2)
+ return (False);
+ fstrcpy(root1, name1);
+ fstrcpy(root2, name2);
+ p = strrchr(root1, '.');
+ if (p)
{
- print_queue_struct *queue = NULL;
- char *p = smb_buf(outbuf) + 3;
- int count = get_printqueue(SNUM(conn), conn, &key, &queue,NULL);
- int num_to_get = ABS(max_count);
- int first = (max_count>0?start_index:start_index+max_count+1);
- int i;
+ *p = 0;
+ fstrcpy(ext1, p + 1);
+ }
+ else
+ {
+ fstrcpy(ext1, "");
+ }
+ p = strrchr(root2, '.');
+ if (p)
+ {
+ *p = 0;
+ fstrcpy(ext2, p + 1);
+ }
+ else
+ {
+ fstrcpy(ext2, "");
+ }
- if (first >= count)
- num_to_get = 0;
+ p = root1;
+ p2 = root2;
+ while (*p2)
+ {
+ if (*p2 == '?')
+ {
+ *p2 = *p;
+ p2++;
+ }
else
- num_to_get = MIN(num_to_get,count-first);
-
-
- for (i=first;i<first+num_to_get;i++) {
- put_dos_date2(p,0,queue[i].time);
- CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
- SSVAL(p,5,printjob_encode(SNUM(conn),
- queue[i].job));
- SIVAL(p,7,queue[i].size);
- CVAL(p,11) = 0;
- StrnCpy(p+12,queue[i].user,16);
- p += 28;
+ {
+ p2++;
}
+ if (*p)
+ p++;
+ }
- if (count > 0) {
- outsize = set_message(outbuf,2,28*count+3,False);
- SSVAL(outbuf,smb_vwv0,count);
- SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,28*count);
+ p = ext1;
+ p2 = ext2;
+ while (*p2)
+ {
+ if (*p2 == '?')
+ {
+ *p2 = *p;
+ p2++;
}
-
- if (queue) free(queue);
-
- DEBUG(3,("%d entries returned in queue\n",count));
+ else
+ {
+ p2++;
+ }
+ if (*p)
+ p++;
}
-
- return(outsize);
-}
-
-
-/****************************************************************************
- reply to a printwrite
-****************************************************************************/
-int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int numtowrite;
- int outsize = set_message(outbuf,0,0,True);
- char *data;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- if (!CAN_PRINT(conn))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
- CHECK_ERROR(fsp);
-
- numtowrite = SVAL(smb_buf(inbuf),1);
- data = smb_buf(inbuf) + 3;
-
- if (write_file(fsp,data,numtowrite) != numtowrite)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
-
- return(outsize);
-}
-
-
-/****************************************************************************
- reply to a mkdir
-****************************************************************************/
-int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- pstring directory;
- int outsize,ret= -1;
- BOOL bad_path = False;
-
- pstrcpy(directory,smb_buf(inbuf) + 1);
- if (!unix_dfs_convert(directory,conn,0,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- if (check_name(directory, conn))
- ret = conn->vfs_ops.mkdir(dos_to_unix(directory,False),
- unix_mode(conn,aDIR));
-
- if (ret < 0)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
- outsize = set_message(outbuf,0,0,True);
-
- DEBUG( 3, ( "mkdir %s ret=%d\n", directory, ret ) );
-
- return(outsize);
-}
-
-/****************************************************************************
-Static function used by reply_rmdir to delete an entire directory
-tree recursively.
-****************************************************************************/
-static BOOL recursive_rmdir(connection_struct *conn, char *directory)
-{
- char *dname = NULL;
- BOOL ret = False;
- void *dirptr = OpenDir(conn, directory, False);
-
- if(dirptr == NULL)
- return True;
-
- while((dname = ReadDirName(dirptr)))
- {
- pstring fullname;
- SMB_STRUCT_STAT st;
-
- if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
- continue;
-
- /* Construct the full name. */
- if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
- {
- errno = ENOMEM;
- ret = True;
- break;
- }
- pstrcpy(fullname, directory);
- pstrcat(fullname, "/");
- pstrcat(fullname, dname);
-
- if(conn->vfs_ops.lstat(dos_to_unix(fullname,False), &st) != 0)
- {
- ret = True;
- break;
- }
-
- if(st.st_mode & S_IFDIR)
- {
- if(recursive_rmdir(conn, fullname)!=0)
- {
- ret = True;
- break;
- }
- if(conn->vfs_ops.rmdir(dos_to_unix(fullname,False)) != 0)
- {
- ret = True;
- break;
- }
- }
- else if(conn->vfs_ops.unlink(dos_to_unix(fullname,False)) != 0)
- {
- ret = True;
- break;
- }
- }
- CloseDir(dirptr);
- return ret;
-}
-
-/****************************************************************************
- reply to a rmdir
-****************************************************************************/
-int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- pstring directory;
- int outsize = 0;
- BOOL ok = False;
- BOOL bad_path = False;
-
- pstrcpy(directory,smb_buf(inbuf) + 1);
- if (!unix_dfs_convert(directory,conn, NULL,&bad_path,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- if (check_name(directory,conn))
- {
-
- dptr_closepath(directory,SVAL(inbuf,smb_pid));
- ok = (conn->vfs_ops.rmdir(dos_to_unix(directory,False)) == 0);
- if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(conn)))
- {
- /* Check to see if the only thing in this directory are
- vetoed files/directories. If so then delete them and
- retry. If we fail to delete any of them (and we *don't*
- do a recursive delete) then fail the rmdir. */
- BOOL all_veto_files = True;
- char *dname;
- void *dirptr = OpenDir(conn, directory, False);
-
- if(dirptr != NULL)
- {
- int dirpos = TellDir(dirptr);
- while ((dname = ReadDirName(dirptr)))
- {
- if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
- continue;
- if(!IS_VETO_PATH(conn, dname))
- {
- all_veto_files = False;
- break;
- }
- }
- if(all_veto_files)
- {
- SeekDir(dirptr,dirpos);
- while ((dname = ReadDirName(dirptr)))
- {
- pstring fullname;
- SMB_STRUCT_STAT st;
-
- if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
- continue;
-
- /* Construct the full name. */
- if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
- {
- errno = ENOMEM;
- break;
- }
- pstrcpy(fullname, directory);
- pstrcat(fullname, "/");
- pstrcat(fullname, dname);
-
- if(conn->vfs_ops.lstat(dos_to_unix(fullname,False),
- &st) != 0)
- break;
- if(st.st_mode & S_IFDIR)
- {
- if(lp_recursive_veto_delete(SNUM(conn)))
- {
- DEBUG(0, ("ERROR: recursive_rmdir()\n"));
- if(recursive_rmdir(conn, fullname) != 0)
- break;
- }
- if(conn->vfs_ops.rmdir(dos_to_unix(fullname,False)) != 0)
- break;
- }
- else if(conn->vfs_ops.unlink(dos_to_unix(fullname,False)) != 0)
- break;
- }
- CloseDir(dirptr);
- /* Retry the rmdir */
- ok = (conn->vfs_ops.rmdir(dos_to_unix(directory,False)) == 0);
- }
- else
- CloseDir(dirptr);
- }
- else
- errno = ENOTEMPTY;
- }
-
- if (!ok)
- DEBUG(3,("couldn't remove directory %s : %s\n",
- directory,strerror(errno)));
- }
-
- if (!ok)
- {
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,ERRbadpath));
- }
-
- outsize = set_message(outbuf,0,0,True);
-
- DEBUG( 3, ( "rmdir %s\n", directory ) );
-
- return(outsize);
-}
+ pstrcpy(name2, root2);
+ if (ext2[0])
+ {
+ pstrcat(name2, ".");
+ pstrcat(name2, ext2);
+ }
-/*******************************************************************
-resolve wildcards in a filename rename
-********************************************************************/
-static BOOL resolve_wildcards(char *name1,char *name2)
-{
- fstring root1,root2;
- fstring ext1,ext2;
- char *p,*p2;
-
- name1 = strrchr(name1,'/');
- name2 = strrchr(name2,'/');
-
- if (!name1 || !name2) return(False);
-
- fstrcpy(root1,name1);
- fstrcpy(root2,name2);
- p = strrchr(root1,'.');
- if (p) {
- *p = 0;
- fstrcpy(ext1,p+1);
- } else {
- fstrcpy(ext1,"");
- }
- p = strrchr(root2,'.');
- if (p) {
- *p = 0;
- fstrcpy(ext2,p+1);
- } else {
- fstrcpy(ext2,"");
- }
-
- p = root1;
- p2 = root2;
- while (*p2) {
- if (*p2 == '?') {
- *p2 = *p;
- p2++;
- } else {
- p2++;
- }
- if (*p) p++;
- }
-
- p = ext1;
- p2 = ext2;
- while (*p2) {
- if (*p2 == '?') {
- *p2 = *p;
- p2++;
- } else {
- p2++;
- }
- if (*p) p++;
- }
-
- pstrcpy(name2,root2);
- if (ext2[0]) {
- pstrcat(name2,".");
- pstrcat(name2,ext2);
- }
-
- return(True);
+ return (True);
}
/*******************************************************************
check if a user is allowed to rename a file
********************************************************************/
-static BOOL can_rename(char *fname,connection_struct *conn)
+static BOOL can_rename(char *fname, connection_struct * conn)
{
- SMB_STRUCT_STAT sbuf;
+ SMB_STRUCT_STAT sbuf;
- if (!CAN_WRITE(conn)) return(False);
+ if (!CAN_WRITE(conn))
+ return (False);
- if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
- if (!check_file_sharing(conn,fname,True)) return(False);
+ if (conn->vfs_ops.lstat(dos_to_unix(fname, False), &sbuf) != 0)
+ return (False);
+ if (!check_file_sharing(conn, fname, True))
+ return (False);
- return(True);
+ return (True);
}
/****************************************************************************
The guts of the rename command, split out so it may be called by the NT SMB
code.
****************************************************************************/
-int rename_internals(connection_struct *conn,
- char *inbuf, char *outbuf, char *name,
+int rename_internals(connection_struct * conn,
+ char *inbuf, char *outbuf, char *name,
char *newname, BOOL replace_if_exists)
{
pstring directory;
BOOL has_wild;
BOOL bad_path1 = False;
BOOL bad_path2 = False;
- int count=0;
+ int count = 0;
int error = ERRnoaccess;
- BOOL exists=False;
+ BOOL exists = False;
*directory = *mask = 0;
- if (!unix_dfs_convert(name,conn,0,&bad_path1,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- if (!unix_dfs_convert(newname,conn,newname_last_component,&bad_path2,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
+ if (!unix_dfs_convert(name, conn, 0, &bad_path1, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+ if (!unix_dfs_convert
+ (newname, conn, newname_last_component, &bad_path2, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
/*
* Split the old name into directory and last component
* name and newname contain a / character or neither of them do
* as this is checked in resolve_wildcards().
*/
-
- p = strrchr(name,'/');
- if (!p) {
- pstrcpy(directory,".");
- pstrcpy(mask,name);
- } else {
+
+ p = strrchr(name, '/');
+ if (!p)
+ {
+ pstrcpy(directory, ".");
+ pstrcpy(mask, name);
+ }
+ else
+ {
*p = 0;
- pstrcpy(directory,name);
- pstrcpy(mask,p+1);
- *p = '/'; /* Replace needed for exceptional test below. */
+ pstrcpy(directory, name);
+ pstrcpy(mask, p + 1);
+ *p = '/'; /* Replace needed for exceptional test below. */
}
if (is_mangled(mask))
- check_mangled_cache( mask );
+ check_mangled_cache(mask);
- has_wild = strchr(mask,'*') || strchr(mask,'?');
+ has_wild = strchr(mask, '*') || strchr(mask, '?');
- if (!has_wild) {
+ if (!has_wild)
+ {
/*
* No wildcards - just process the one file.
*/
BOOL is_short_name = is_8_3(name, True);
/* Add a terminating '/' to the directory name. */
- pstrcat(directory,"/");
- pstrcat(directory,mask);
-
+ pstrcat(directory, "/");
+ pstrcat(directory, mask);
+
/* Ensure newname contains a '/' also */
- if(strrchr(newname,'/') == 0) {
+ if (strrchr(newname, '/') == 0)
+ {
pstring tmpstr;
-
+
pstrcpy(tmpstr, "./");
pstrcat(tmpstr, newname);
pstrcpy(newname, tmpstr);
}
-
- DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
- case_sensitive, case_preserve, short_case_preserve, directory,
- newname, newname_last_component, is_short_name));
+
+ DEBUG(3,
+ ("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
+ case_sensitive, case_preserve, short_case_preserve,
+ directory, newname, newname_last_component,
+ is_short_name));
/*
* Check for special case with case preserving and not
* the rename (user is trying to change the case of the
* filename).
*/
- if((case_sensitive == False) &&
- (((case_preserve == True) &&
- (is_short_name == False)) ||
- ((short_case_preserve == True) &&
- (is_short_name == True))) &&
- strcsequal(directory, newname)) {
+ if ((case_sensitive == False) &&
+ (((case_preserve == True) &&
+ (is_short_name == False)) ||
+ ((short_case_preserve == True) &&
+ (is_short_name == True))) &&
+ strcsequal(directory, newname))
+ {
pstring newname_modified_last_component;
/*
* Note that we guarantee that newname contains a '/'
* character above.
*/
- p = strrchr(newname,'/');
- pstrcpy(newname_modified_last_component,p+1);
-
- if(strcsequal(newname_modified_last_component,
- newname_last_component) == False) {
+ p = strrchr(newname, '/');
+ pstrcpy(newname_modified_last_component, p + 1);
+
+ if (strcsequal(newname_modified_last_component,
+ newname_last_component) == False)
+ {
/*
* Replace the modified last component with
* the original.
*/
- pstrcpy(p+1, newname_last_component);
+ pstrcpy(p + 1, newname_last_component);
}
}
-
- if(replace_if_exists) {
+
+ if (replace_if_exists)
+ {
/*
* NT SMB specific flag - rename can overwrite
* file with the same name so don't check for
* dos_file_exist().
*/
- if(resolve_wildcards(directory,newname) &&
- can_rename(directory,conn) &&
- !conn->vfs_ops.rename(dos_to_unix(directory,False),
- newname))
+ if (resolve_wildcards(directory, newname) &&
+ can_rename(directory, conn) &&
+ !conn->vfs_ops.
+ rename(dos_to_unix(directory, False), newname))
count++;
- } else {
- if (resolve_wildcards(directory,newname) &&
- can_rename(directory,conn) &&
- !vfs_file_exist(conn,dos_to_unix(newname,False),NULL) &&
- !conn->vfs_ops.rename(dos_to_unix(directory,False),
- newname))
+ }
+ else
+ {
+ if (resolve_wildcards(directory, newname) &&
+ can_rename(directory, conn) &&
+ !vfs_file_exist(conn, dos_to_unix(newname, False),
+ NULL)
+ && !conn->vfs_ops.
+ rename(dos_to_unix(directory, False), newname))
count++;
}
- DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
- directory,newname));
-
- if (!count) exists = vfs_file_exist(conn,dos_to_unix(directory,False),NULL);
- if (!count && exists && vfs_file_exist(conn,dos_to_unix(newname,False),NULL)) {
- exists = True;
- error = ERRrename;
- }
- } else {
- /*
- * Wildcards - process each file that matches.
- */
+ DEBUG(3,
+ ("rename_internals: %s doing rename on %s -> %s\n",
+ (count != 0) ? "succeeded" : "failed", directory,
+ newname));
+
+ if (!count)
+ exists =
+ vfs_file_exist(conn,
+ dos_to_unix(directory, False),
+ NULL);
+ if (!count && exists
+ && vfs_file_exist(conn, dos_to_unix(newname, False),
+ NULL))
+ {
+ exists = True;
+ error = ERRrename;
+ }
+ }
+ else
+ {
+ /*
+ * Wildcards - process each file that matches.
+ */
+ void *dirptr = NULL;
+ char *dname;
+ pstring destname;
+
+ if (check_name(directory, conn))
+ dirptr = OpenDir(conn, directory, True);
+
+ if (dirptr)
+ {
+ error = ERRbadfile;
+
+ if (strequal(mask, "????????.???"))
+ pstrcpy(mask, "*");
+
+ while ((dname = ReadDirName(dirptr)))
+ {
+ pstring fname;
+ pstrcpy(fname, dname);
+
+ if (!mask_match
+ (fname, mask, case_sensitive, False))
+ continue;
+
+ error = ERRnoaccess;
+ slprintf(fname, sizeof(fname) - 1, "%s/%s",
+ directory, dname);
+ if (!can_rename(fname, conn))
+ {
+ DEBUG(6,
+ ("rename %s refused\n", fname));
+ continue;
+ }
+ pstrcpy(destname, newname);
+
+ if (!resolve_wildcards(fname, destname))
+ {
+ DEBUG(6,
+ ("resolve_wildcards %s %s failed\n",
+ fname, destname));
+ continue;
+ }
+
+ if (!replace_if_exists
+ && vfs_file_exist(conn,
+ dos_to_unix(destname,
+ False),
+ NULL))
+ {
+ DEBUG(6,
+ ("file_exist %s\n", destname));
+ error = 183;
+ continue;
+ }
+
+ if (!conn->vfs_ops.
+ rename(dos_to_unix(fname, False),
+ destname))
+ count++;
+ DEBUG(3,
+ ("rename_internals: doing rename on %s -> %s\n",
+ fname, destname));
+ }
+ CloseDir(dirptr);
+ }
+ }
+
+ if (count == 0)
+ {
+ if (exists)
+ return (ERROR(ERRDOS, error));
+ else
+ {
+ if ((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return (UNIXERROR(ERRDOS, error));
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Reply to a mv.
+****************************************************************************/
+
+int reply_mv(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ int outsize = 0;
+ pstring name;
+ pstring newname;
+
+ pstrcpy(name, smb_buf(inbuf) + 1);
+ pstrcpy(newname, smb_buf(inbuf) + 3 + strlen(name));
+
+ DEBUG(3, ("reply_mv : %s -> %s\n", name, newname));
+
+ outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
+ if (outsize == 0)
+ outsize = set_message(outbuf, 0, 0, True);
+
+ return (outsize);
+}
+
+/*******************************************************************
+ copy a file as part of a reply_copy
+ ******************************************************************/
+
+static BOOL copy_file(char *src, char *dest1, connection_struct * conn,
+ int ofun, int count, BOOL target_is_directory)
+{
+ int Access, action;
+ SMB_STRUCT_STAT st;
+ int ret = -1;
+ files_struct *fsp1, *fsp2;
+ pstring dest;
+
+ pstrcpy(dest, dest1);
+ if (target_is_directory)
+ {
+ char *p = strrchr(src, '/');
+ if (p)
+ p++;
+ else
+ p = src;
+ pstrcat(dest, "/");
+ pstrcat(dest, p);
+ }
+
+ if (!vfs_file_exist(conn, dos_to_unix(src, False), &st))
+ return (False);
+
+ fsp1 = file_new();
+ if (!fsp1)
+ return (False);
+
+ open_file_shared(fsp1, conn, src,
+ SET_DENY_MODE(DENY_NONE) |
+ SET_OPEN_MODE(DOS_OPEN_RDONLY),
+ (FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN), 0, 0,
+ &Access, &action);
+
+ if (!fsp1->open)
+ {
+ file_free(fsp1);
+ return (False);
+ }
+
+ if (!target_is_directory && count)
+ ofun = 1;
+
+ fsp2 = file_new();
+ if (!fsp2)
+ {
+ close_file(fsp1, False);
+ return (False);
+ }
+ open_file_shared(fsp2, conn, dest,
+ SET_DENY_MODE(DENY_NONE) |
+ SET_OPEN_MODE(DOS_OPEN_WRONLY), ofun, st.st_mode, 0,
+ &Access, &action);
+
+ if (!fsp2->open)
+ {
+ close_file(fsp1, False);
+ file_free(fsp2);
+ return (False);
+ }
+
+ if ((ofun & 3) == 1)
+ {
+ if (conn->vfs_ops.lseek(fsp2->fd_ptr->fd, 0, SEEK_END) == -1)
+ {
+ DEBUG(0,
+ ("copy_file: error - sys_lseek returned error %s\n",
+ strerror(errno)));
+ /*
+ * Stop the copy from occurring.
+ */
+ ret = -1;
+ st.st_size = 0;
+ }
+ }
+
+ if (st.st_size)
+ ret =
+ vfs_transfer_file(-1, fsp1, -1, fsp2, st.st_size,
+ NULL, 0, 0);
+
+ close_file(fsp1, False);
+ close_file(fsp2, False);
+
+ return (ret == st.st_size);
+}
+
+
+
+/****************************************************************************
+ reply to a file copy.
+ ****************************************************************************/
+int reply_copy(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
+{
+ int outsize = 0;
+ pstring name;
+ pstring directory;
+ pstring mask, newname;
+ char *p;
+ int count = 0;
+ int error = ERRnoaccess;
+ BOOL has_wild;
+ BOOL exists = False;
+ int tid2 = SVAL(inbuf, smb_vwv0);
+ int ofun = SVAL(inbuf, smb_vwv1);
+ int flags = SVAL(inbuf, smb_vwv2);
+ BOOL target_is_directory = False;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
+
+ *directory = *mask = 0;
+
+ pstrcpy(name, smb_buf(inbuf));
+ pstrcpy(newname, smb_buf(inbuf) + 1 + strlen(name));
+
+ DEBUG(3, ("reply_copy : %s -> %s\n", name, newname));
+
+ if (tid2 != conn->cnum)
+ {
+ /* can't currently handle inter share copies XXXX */
+ DEBUG(3, ("Rejecting inter-share copy\n"));
+ return (ERROR(ERRSRV, ERRinvdevice));
+ }
+
+ if (!unix_dfs_convert(name, conn, 0, &bad_path1, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+ if (!unix_dfs_convert(newname, conn, 0, &bad_path2, NULL))
+ {
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return (ERROR(0, 0xc0000000 | NT_STATUS_PATH_NOT_COVERED));
+ }
+
+ target_is_directory = dos_directory_exist(newname, NULL);
+
+ if ((flags & 1) && target_is_directory)
+ {
+ return (ERROR(ERRDOS, ERRbadfile));
+ }
+
+ if ((flags & 2) && !target_is_directory)
+ {
+ return (ERROR(ERRDOS, ERRbadpath));
+ }
+
+ if ((flags & (1 << 5)) && dos_directory_exist(name, NULL))
+ {
+ /* wants a tree copy! XXXX */
+ DEBUG(3, ("Rejecting tree copy\n"));
+ return (ERROR(ERRSRV, ERRerror));
+ }
+
+ p = strrchr(name, '/');
+ if (!p)
+ {
+ pstrcpy(directory, "./");
+ pstrcpy(mask, name);
+ }
+ else
+ {
+ *p = 0;
+ pstrcpy(directory, name);
+ pstrcpy(mask, p + 1);
+ }
+
+ if (is_mangled(mask))
+ check_mangled_cache(mask);
+
+ has_wild = strchr(mask, '*') || strchr(mask, '?');
+
+ if (!has_wild)
+ {
+ pstrcat(directory, "/");
+ pstrcat(directory, mask);
+ if (resolve_wildcards(directory, newname) &&
+ copy_file(directory, newname, conn, ofun,
+ count, target_is_directory)) count++;
+ if (!count)
+ exists =
+ vfs_file_exist(conn,
+ dos_to_unix(directory, False),
+ NULL);
+ }
+ else
+ {
void *dirptr = NULL;
char *dname;
pstring destname;
-
- if (check_name(directory,conn))
+
+ if (check_name(directory, conn))
dirptr = OpenDir(conn, directory, True);
-
- if (dirptr) {
+
+ if (dirptr)
+ {
error = ERRbadfile;
-
- if (strequal(mask,"????????.???"))
- pstrcpy(mask,"*");
-
- while ((dname = ReadDirName(dirptr))) {
+
+ if (strequal(mask, "????????.???"))
+ pstrcpy(mask, "*");
+
+ while ((dname = ReadDirName(dirptr)))
+ {
pstring fname;
- pstrcpy(fname,dname);
-
- if(!mask_match(fname, mask, case_sensitive, False))
- continue;
-
+ pstrcpy(fname, dname);
+
+ if (!mask_match
+ (fname, mask, case_sensitive,
+ False)) continue;
+
error = ERRnoaccess;
- slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
- if (!can_rename(fname,conn)) {
- DEBUG(6,("rename %s refused\n", fname));
- continue;
- }
- pstrcpy(destname,newname);
-
- if (!resolve_wildcards(fname,destname)) {
- DEBUG(6,("resolve_wildcards %s %s failed\n", fname, destname));
- continue;
- }
-
- if (!replace_if_exists && vfs_file_exist(conn,dos_to_unix(destname,False),NULL)) {
- DEBUG(6,("file_exist %s\n", destname));
- error = 183;
- continue;
- }
-
- if (!conn->vfs_ops.rename(dos_to_unix(fname,False),destname))
+ slprintf(fname, sizeof(fname) - 1, "%s/%s",
+ directory, dname);
+ pstrcpy(destname, newname);
+ if (resolve_wildcards(fname, destname) &&
+ copy_file(directory, newname, conn, ofun,
+ count, target_is_directory))
count++;
- DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
+ DEBUG(3,
+ ("reply_copy : doing copy on %s -> %s\n",
+ fname, destname));
}
CloseDir(dirptr);
}
}
-
- if (count == 0) {
+
+ if (count == 0)
+ {
if (exists)
- return(ERROR(ERRDOS,error));
- else {
- if((errno == ENOENT) && (bad_path1 || bad_path2)) {
+ return (ERROR(ERRDOS, error));
+ else
+ {
+ if ((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
unix_ERR_class = ERRDOS;
unix_ERR_code = ERRbadpath;
}
- return(UNIXERROR(ERRDOS,error));
+ return (UNIXERROR(ERRDOS, error));
}
}
-
- return 0;
+
+ outsize = set_message(outbuf, 1, 0, True);
+ SSVAL(outbuf, smb_vwv0, count);
+
+ return (outsize);
}
/****************************************************************************
- Reply to a mv.
+ reply to a setdir
****************************************************************************/
-
-int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_setdir(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- int outsize = 0;
- pstring name;
- pstring newname;
-
- pstrcpy(name,smb_buf(inbuf) + 1);
- pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
-
- DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
-
- outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
- if(outsize == 0)
- outsize = set_message(outbuf,0,0,True);
-
- return(outsize);
-}
+ int snum;
+ int outsize = 0;
+ BOOL ok = False;
+ pstring newdir;
-/*******************************************************************
- copy a file as part of a reply_copy
- ******************************************************************/
+ snum = SNUM(conn);
+ if (!CAN_SETDIR(snum))
+ return (ERROR(ERRDOS, ERRnoaccess));
-static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
- int count,BOOL target_is_directory)
-{
- int Access,action;
- SMB_STRUCT_STAT st;
- int ret=-1;
- files_struct *fsp1,*fsp2;
- pstring dest;
-
- pstrcpy(dest,dest1);
- if (target_is_directory) {
- char *p = strrchr(src,'/');
- if (p)
- p++;
- else
- p = src;
- pstrcat(dest,"/");
- pstrcat(dest,p);
- }
-
- if (!vfs_file_exist(conn,dos_to_unix(src,False),&st))
- return(False);
-
- fsp1 = file_new();
- if (!fsp1)
- return(False);
-
- open_file_shared(fsp1, conn, src,
- SET_DENY_MODE(DENY_NONE) | SET_OPEN_MODE(DOS_OPEN_RDONLY),
- (FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN), 0, 0, &Access, &action);
-
- if (!fsp1->open) {
- file_free(fsp1);
- return(False);
- }
-
- if (!target_is_directory && count)
- ofun = 1;
-
- fsp2 = file_new();
- if (!fsp2) {
- close_file(fsp1,False);
- return(False);
- }
- open_file_shared(fsp2, conn, dest,
- SET_DENY_MODE(DENY_NONE) | SET_OPEN_MODE(DOS_OPEN_WRONLY),
- ofun, st.st_mode, 0, &Access, &action);
-
- if (!fsp2->open) {
- close_file(fsp1,False);
- file_free(fsp2);
- return(False);
- }
-
- if ((ofun&3) == 1) {
- if(conn->vfs_ops.lseek(fsp2->fd_ptr->fd,0,SEEK_END) == -1) {
- DEBUG(0,("copy_file: error - sys_lseek returned error %s\n",
- strerror(errno) ));
- /*
- * Stop the copy from occurring.
- */
- ret = -1;
- st.st_size = 0;
- }
- }
-
- if (st.st_size)
- ret = vfs_transfer_file(-1, fsp1, -1, fsp2, st.st_size, NULL, 0, 0);
-
- close_file(fsp1,False);
- close_file(fsp2,False);
-
- return(ret == st.st_size);
-}
+ pstrcpy(newdir, smb_buf(inbuf) + 1);
+ strlower(newdir);
+ if (strlen(newdir) == 0)
+ {
+ ok = True;
+ }
+ else
+ {
+ ok = dos_directory_exist(newdir, NULL);
+ if (ok)
+ {
+ string_set(&conn->connectpath, newdir);
+ }
+ }
+ if (!ok)
+ return (ERROR(ERRDOS, ERRbadpath));
-/****************************************************************************
- reply to a file copy.
- ****************************************************************************/
-int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int outsize = 0;
- pstring name;
- pstring directory;
- pstring mask,newname;
- char *p;
- int count=0;
- int error = ERRnoaccess;
- BOOL has_wild;
- BOOL exists=False;
- int tid2 = SVAL(inbuf,smb_vwv0);
- int ofun = SVAL(inbuf,smb_vwv1);
- int flags = SVAL(inbuf,smb_vwv2);
- BOOL target_is_directory=False;
- BOOL bad_path1 = False;
- BOOL bad_path2 = False;
-
- *directory = *mask = 0;
-
- pstrcpy(name,smb_buf(inbuf));
- pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
-
- DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
-
- if (tid2 != conn->cnum) {
- /* can't currently handle inter share copies XXXX */
- DEBUG(3,("Rejecting inter-share copy\n"));
- return(ERROR(ERRSRV,ERRinvdevice));
- }
-
- if (!unix_dfs_convert(name,conn,0,&bad_path1,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
- if (!unix_dfs_convert(newname,conn,0,&bad_path2,NULL))
- {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
- return(ERROR(0, 0xc0000000|NT_STATUS_PATH_NOT_COVERED));
- }
-
- target_is_directory = dos_directory_exist(newname,NULL);
-
- if ((flags&1) && target_is_directory) {
- return(ERROR(ERRDOS,ERRbadfile));
- }
-
- if ((flags&2) && !target_is_directory) {
- return(ERROR(ERRDOS,ERRbadpath));
- }
-
- if ((flags&(1<<5)) && dos_directory_exist(name,NULL)) {
- /* wants a tree copy! XXXX */
- DEBUG(3,("Rejecting tree copy\n"));
- return(ERROR(ERRSRV,ERRerror));
- }
-
- p = strrchr(name,'/');
- if (!p) {
- pstrcpy(directory,"./");
- pstrcpy(mask,name);
- } else {
- *p = 0;
- pstrcpy(directory,name);
- pstrcpy(mask,p+1);
- }
-
- if (is_mangled(mask))
- check_mangled_cache( mask );
-
- has_wild = strchr(mask,'*') || strchr(mask,'?');
-
- if (!has_wild) {
- pstrcat(directory,"/");
- pstrcat(directory,mask);
- if (resolve_wildcards(directory,newname) &&
- copy_file(directory,newname,conn,ofun,
- count,target_is_directory)) count++;
- if (!count) exists = vfs_file_exist(conn,dos_to_unix(directory,False),NULL);
- } else {
- void *dirptr = NULL;
- char *dname;
- pstring destname;
-
- if (check_name(directory,conn))
- dirptr = OpenDir(conn, directory, True);
-
- if (dirptr)
- {
- error = ERRbadfile;
-
- if (strequal(mask,"????????.???"))
- pstrcpy(mask,"*");
+ outsize = set_message(outbuf, 0, 0, True);
+ CVAL(outbuf, smb_reh) = CVAL(inbuf, smb_reh);
- while ((dname = ReadDirName(dirptr)))
- {
- pstring fname;
- pstrcpy(fname,dname);
-
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
-
- error = ERRnoaccess;
- slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
- pstrcpy(destname,newname);
- if (resolve_wildcards(fname,destname) &&
- copy_file(directory,newname,conn,ofun,
- count,target_is_directory)) count++;
- DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
- }
- CloseDir(dirptr);
- }
- }
-
- if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else
- {
- if((errno == ENOENT) && (bad_path1 || bad_path2))
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return(UNIXERROR(ERRDOS,error));
- }
- }
-
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,count);
-
- return(outsize);
-}
+ DEBUG(3, ("setdir %s\n", newdir));
-/****************************************************************************
- reply to a setdir
-****************************************************************************/
-int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
- int snum;
- int outsize = 0;
- BOOL ok = False;
- pstring newdir;
-
- snum = SNUM(conn);
- if (!CAN_SETDIR(snum))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- pstrcpy(newdir,smb_buf(inbuf) + 1);
- strlower(newdir);
-
- if (strlen(newdir) == 0) {
- ok = True;
- } else {
- ok = dos_directory_exist(newdir,NULL);
- if (ok) {
- string_set(&conn->connectpath,newdir);
- }
- }
-
- if (!ok)
- return(ERROR(ERRDOS,ERRbadpath));
-
- outsize = set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
-
- DEBUG(3,("setdir %s\n", newdir));
-
- return(outsize);
+ return (outsize);
}
/****************************************************************************
reply to a lockingX request
****************************************************************************/
-int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+int reply_lockingX(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
{
- files_struct *fsp = file_fsp(inbuf,smb_vwv2);
- uchar locktype = CVAL(inbuf,smb_vwv3);
+ files_struct *fsp = file_fsp(inbuf, smb_vwv2);
+ uchar locktype = CVAL(inbuf, smb_vwv3);
#if 0
- uchar oplocklevel = CVAL(inbuf,smb_vwv3+1);
+ uchar oplocklevel = CVAL(inbuf, smb_vwv3 + 1);
#endif
- uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
- uint16 num_locks = SVAL(inbuf,smb_vwv7);
- SMB_OFF_T count = 0, offset = 0;
- int32 lock_timeout = IVAL(inbuf,smb_vwv4);
- int i;
- char *data;
- uint32 ecode=0, dummy2;
- int eclass=0, dummy1;
- BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
- CHECK_FSP(fsp,conn);
- CHECK_ERROR(fsp);
-
- data = smb_buf(inbuf);
-
- /* Check if this is an oplock break on a file
- we have granted an oplock on.
- */
- if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
- {
- SMB_DEV_T dev = fsp->fd_ptr->dev;
- SMB_INO_T inode = fsp->fd_ptr->inode;
-
- DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
- fsp->fnum));
- /*
- * Make sure we have granted an oplock on this file.
- */
- if(!fsp->granted_oplock)
- {
- DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
-no oplock granted on this file.\n", fsp->fnum));
- return ERROR(ERRDOS,ERRlock);
- }
-
- /* Remove the oplock flag from the sharemode. */
- lock_share_entry(fsp->conn, dev, inode);
- if(remove_share_oplock(fsp)==False) {
-
- DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
-dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
-
- unlock_share_entry(fsp->conn, dev, inode);
- } else {
- unlock_share_entry(fsp->conn, dev, inode);
-
- /* Clear the granted flag and return. */
- fsp->granted_oplock = False;
- }
-
- /* if this is a pure oplock break request then don't send a reply */
- if (num_locks == 0 && num_ulocks == 0)
- {
- /* Sanity check - ensure a pure oplock break is not a
- chained request. */
- if(CVAL(inbuf,smb_vwv0) != 0xff)
- DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
- (unsigned int)CVAL(inbuf,smb_vwv0) ));
- return -1;
- }
- }
-
- /* Data now points at the beginning of the list
- of smb_unlkrng structs */
- for(i = 0; i < (int)num_ulocks; i++) {
- if(!large_file_format) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- }
+ uint16 num_ulocks = SVAL(inbuf, smb_vwv6);
+ uint16 num_locks = SVAL(inbuf, smb_vwv7);
+ SMB_OFF_T count = 0, offset = 0;
+ int32 lock_timeout = IVAL(inbuf, smb_vwv4);
+ int i;
+ char *data;
+ uint32 ecode = 0, dummy2;
+ int eclass = 0, dummy1;
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ CHECK_FSP(fsp, conn);
+ CHECK_ERROR(fsp);
+
+ data = smb_buf(inbuf);
+
+ /* Check if this is an oplock break on a file
+ we have granted an oplock on.
+ */
+ if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
+ {
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+
+ DEBUG(5,
+ ("reply_lockingX: oplock break reply from client for fnum = %d\n",
+ fsp->fnum));
+ /*
+ * Make sure we have granted an oplock on this file.
+ */
+ if (!fsp->granted_oplock)
+ {
+ DEBUG(0,
+ ("reply_lockingX: Error : oplock break from client for fnum = %d and \
+no oplock granted on this file.\n",
+ fsp->fnum));
+ return ERROR(ERRDOS, ERRlock);
+ }
+
+ /* Remove the oplock flag from the sharemode. */
+ lock_share_entry(fsp->conn, dev, inode);
+ if (remove_share_oplock(fsp) == False)
+ {
+
+ DEBUG(0,
+ ("reply_lockingX: failed to remove share oplock for fnum %d, \
+dev = %x, inode = %.0f\n",
+ fsp->fnum, (unsigned int)dev, (double)inode));
+
+ unlock_share_entry(fsp->conn, dev, inode);
+ }
+ else
+ {
+ unlock_share_entry(fsp->conn, dev, inode);
+
+ /* Clear the granted flag and return. */
+ fsp->granted_oplock = False;
+ }
+
+ /* if this is a pure oplock break request then don't send a reply */
+ if (num_locks == 0 && num_ulocks == 0)
+ {
+ /* Sanity check - ensure a pure oplock break is not a
+ chained request. */
+ if (CVAL(inbuf, smb_vwv0) != 0xff)
+ DEBUG(0,
+ ("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
+ (unsigned int)CVAL(inbuf, smb_vwv0)));
+ return -1;
+ }
+ }
+
+ /* Data now points at the beginning of the list
+ of smb_unlkrng structs */
+ for (i = 0; i < (int)num_ulocks; i++)
+ {
+ if (!large_file_format)
+ {
+ count = IVAL(data, SMB_LKLEN_OFFSET(i));
+ offset = IVAL(data, SMB_LKOFF_OFFSET(i));
+ }
#ifdef LARGE_SMB_OFF_T
- else {
- count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
- offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
- }
+ else
+ {
+ count =
+ (((SMB_OFF_T)
+ IVAL(data,
+ SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32)
+ | ((SMB_OFF_T)
+ IVAL(data, SMB_LARGE_LKLEN_OFFSET_LOW(i)));
+ offset =
+ (((SMB_OFF_T)
+ IVAL(data,
+ SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32)
+ | ((SMB_OFF_T)
+ IVAL(data, SMB_LARGE_LKOFF_OFFSET_LOW(i)));
+ }
#endif /* LARGE_SMB_OFF_T */
- DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for file %s\n",
- (double)offset, (double)count, fsp->fsp_name ));
+ DEBUG(10,
+ ("reply_lockingX: unlock start=%.0f, len=%.0f for file %s\n",
+ (double)offset, (double)count, fsp->fsp_name));
- if(!do_unlock(fsp,conn,count,offset,&eclass, &ecode))
- return ERROR(eclass,ecode);
- }
+ if (!do_unlock(fsp, conn, count, offset, &eclass, &ecode))
+ return ERROR(eclass, ecode);
+ }
- /* Setup the timeout in seconds. */
- lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
+ /* Setup the timeout in seconds. */
+ lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout / 1000);
- /* Now do any requested locks */
- data += ((large_file_format ? 20 : 10)*num_ulocks);
+ /* Now do any requested locks */
+ data += ((large_file_format ? 20 : 10) * num_ulocks);
- /* Data now points at the beginning of the list
- of smb_lkrng structs */
+ /* Data now points at the beginning of the list
+ of smb_lkrng structs */
- for(i = 0; i < (int)num_locks; i++) {
- if(!large_file_format) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- }
+ for (i = 0; i < (int)num_locks; i++)
+ {
+ if (!large_file_format)
+ {
+ count = IVAL(data, SMB_LKLEN_OFFSET(i));
+ offset = IVAL(data, SMB_LKOFF_OFFSET(i));
+ }
#ifdef LARGE_SMB_OFF_T
- else {
- count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
- offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
- }
+ else
+ {
+ count =
+ (((SMB_OFF_T)
+ IVAL(data,
+ SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32)
+ | ((SMB_OFF_T)
+ IVAL(data, SMB_LARGE_LKLEN_OFFSET_LOW(i)));
+ offset =
+ (((SMB_OFF_T)
+ IVAL(data,
+ SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32)
+ | ((SMB_OFF_T)
+ IVAL(data, SMB_LARGE_LKOFF_OFFSET_LOW(i)));
+ }
#endif /* LARGE_SMB_OFF_T */
-
- DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for file %s\n",
- (double)offset, (double)count, fsp->fsp_name ));
-
- if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? F_RDLCK : F_WRLCK),
- &eclass, &ecode)) {
- if((ecode == ERRlock) && (lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
- /*
- * A blocking lock was requested. Package up
- * this smb into a queued request and push it
- * onto the blocking lock queue.
- */
- if(push_blocking_lock_request(inbuf, length, lock_timeout, i))
- return -1;
- }
- break;
- }
- }
-
- /* If any of the above locks failed, then we must unlock
- all of the previous locks (X/Open spec). */
- if(i != num_locks && num_locks != 0) {
- for(; i >= 0; i--) {
- if(!large_file_format) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- }
+
+ DEBUG(10,
+ ("reply_lockingX: lock start=%.0f, len=%.0f for file %s\n",
+ (double)offset, (double)count, fsp->fsp_name));
+
+ if (!do_lock
+ (fsp, conn, count, offset,
+ ((locktype & 1) ? F_RDLCK : F_WRLCK), &eclass, &ecode))
+ {
+ if ((ecode == ERRlock) && (lock_timeout != 0)
+ && lp_blocking_locks(SNUM(conn)))
+ {
+ /*
+ * A blocking lock was requested. Package up
+ * this smb into a queued request and push it
+ * onto the blocking lock queue.
+ */
+ if (push_blocking_lock_request
+ (inbuf, length, lock_timeout, i))
+ return -1;
+ }
+ break;
+ }
+ }
+
+ /* If any of the above locks failed, then we must unlock
+ all of the previous locks (X/Open spec). */
+ if (i != num_locks && num_locks != 0)
+ {
+ for (; i >= 0; i--)
+ {
+ if (!large_file_format)
+ {
+ count = IVAL(data, SMB_LKLEN_OFFSET(i));
+ offset = IVAL(data, SMB_LKOFF_OFFSET(i));
+ }
#ifdef LARGE_SMB_OFF_T
- else {
- count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
- offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
- ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
- }
+ else
+ {
+ count =
+ (((SMB_OFF_T)
+ IVAL(data,
+ SMB_LARGE_LKLEN_OFFSET_HIGH
+ (i))) << 32) | ((SMB_OFF_T)
+ IVAL(data,
+ SMB_LARGE_LKLEN_OFFSET_LOW
+ (i)));
+ offset =
+ (((SMB_OFF_T)
+ IVAL(data,
+ SMB_LARGE_LKOFF_OFFSET_HIGH
+ (i))) << 32) | ((SMB_OFF_T)
+ IVAL(data,
+ SMB_LARGE_LKOFF_OFFSET_LOW
+ (i)));
+ }
#endif /* LARGE_SMB_OFF_T */
- do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
- }
- return ERROR(eclass,ecode);
- }
+ do_unlock(fsp, conn, count, offset, &dummy1, &dummy2);
+ }
+ return ERROR(eclass, ecode);
+ }
- set_message(outbuf,2,0,True);
-
- DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
- fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
+ set_message(outbuf, 2, 0, True);
- return chain_reply(inbuf,outbuf,length,bufsize);
+ DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
+ fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
+
+ return chain_reply(inbuf, outbuf, length, bufsize);
}
/****************************************************************************
reply to a SMBreadbmpx (read block multiplex) request
****************************************************************************/
-int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+int reply_readbmpx(connection_struct * conn, char *inbuf, char *outbuf,
+ int length, int bufsize)
{
- ssize_t nread = -1;
- ssize_t total_read;
- char *data;
- SMB_OFF_T startpos;
- int outsize;
- size_t maxcount;
- int max_per_packet;
- size_t tcount;
- int pad;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- /* this function doesn't seem to work - disable by default */
- if (!lp_readbmpx())
- return(ERROR(ERRSRV,ERRuseSTD));
-
- outsize = set_message(outbuf,8,0,True);
-
- CHECK_FSP(fsp,conn);
- CHECK_READ(fsp);
- CHECK_ERROR(fsp);
-
- startpos = IVAL(inbuf,smb_vwv1);
- maxcount = SVAL(inbuf,smb_vwv3);
-
- data = smb_buf(outbuf);
- pad = ((long)data)%4;
- if (pad) pad = 4 - pad;
- data += pad;
-
- max_per_packet = bufsize-(outsize+pad);
- tcount = maxcount;
- total_read = 0;
-
- if (is_locked(fsp,conn,maxcount,startpos, F_RDLCK))
- return(ERROR(ERRDOS,ERRlock));
-
- do
- {
- size_t N = MIN(max_per_packet,tcount-total_read);
-
- nread = read_file(fsp,data,startpos,N);
-
- if (nread <= 0) nread = 0;
-
- if (nread < (ssize_t)N)
- tcount = total_read + nread;
-
- set_message(outbuf,8,nread,False);
- SIVAL(outbuf,smb_vwv0,startpos);
- SSVAL(outbuf,smb_vwv2,tcount);
- SSVAL(outbuf,smb_vwv6,nread);
- SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
-
- send_smb(Client,outbuf);
-
- total_read += nread;
- startpos += nread;
- }
- while (total_read < (ssize_t)tcount);
-
- return(-1);
+ ssize_t nread = -1;
+ ssize_t total_read;
+ char *data;
+ SMB_OFF_T startpos;
+ int outsize;
+ size_t maxcount;
+ int max_per_packet;
+ size_t tcount;
+ int pad;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ /* this function doesn't seem to work - disable by default */
+ if (!lp_readbmpx())
+ return (ERROR(ERRSRV, ERRuseSTD));
+
+ outsize = set_message(outbuf, 8, 0, True);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
+
+ startpos = IVAL(inbuf, smb_vwv1);
+ maxcount = SVAL(inbuf, smb_vwv3);
+
+ data = smb_buf(outbuf);
+ pad = ((long)data) % 4;
+ if (pad)
+ pad = 4 - pad;
+ data += pad;
+
+ max_per_packet = bufsize - (outsize + pad);
+ tcount = maxcount;
+ total_read = 0;
+
+ if (is_locked(fsp, conn, maxcount, startpos, F_RDLCK))
+ return (ERROR(ERRDOS, ERRlock));
+
+ do
+ {
+ size_t N = MIN(max_per_packet, tcount - total_read);
+
+ nread = read_file(fsp, data, startpos, N);
+
+ if (nread <= 0)
+ nread = 0;
+
+ if (nread < (ssize_t) N)
+ tcount = total_read + nread;
+
+ set_message(outbuf, 8, nread, False);
+ SIVAL(outbuf, smb_vwv0, startpos);
+ SSVAL(outbuf, smb_vwv2, tcount);
+ SSVAL(outbuf, smb_vwv6, nread);
+ SSVAL(outbuf, smb_vwv7, smb_offset(data, outbuf));
+
+ send_smb(Client, outbuf);
+
+ total_read += nread;
+ startpos += nread;
+ }
+ while (total_read < (ssize_t) tcount);
+
+ return (-1);
}
/****************************************************************************
reply to a SMBwritebmpx (write block multiplex primary) request
****************************************************************************/
-int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_writebmpx(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- size_t numtowrite;
- ssize_t nwritten = -1;
- int outsize = 0;
- SMB_OFF_T startpos;
- size_t tcount;
- BOOL write_through;
- int smb_doff;
- char *data;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
- CHECK_ERROR(fsp);
-
- tcount = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv3);
- write_through = BITSETW(inbuf+smb_vwv7,0);
- numtowrite = SVAL(inbuf,smb_vwv10);
- smb_doff = SVAL(inbuf,smb_vwv11);
-
- data = smb_base(inbuf) + smb_doff;
-
- /* If this fails we need to send an SMBwriteC response,
- not an SMBwritebmpx - set this up now so we don't forget */
- CVAL(outbuf,smb_com) = SMBwritec;
-
- if (is_locked(fsp,conn,tcount,startpos,F_WRLCK))
- return(ERROR(ERRDOS,ERRlock));
-
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- nwritten = write_file(fsp,data,numtowrite);
-
- if((lp_syncalways(SNUM(conn)) || write_through) &&
- lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
-
- if(nwritten < (ssize_t)numtowrite)
- return(UNIXERROR(ERRHRD,ERRdiskfull));
-
- /* If the maximum to be written to this file
- is greater than what we just wrote then set
- up a secondary struct to be attached to this
- fd, we will use this to cache error messages etc. */
- if((ssize_t)tcount > nwritten)
- {
- write_bmpx_struct *wbms;
- if(fsp->wbmpx_ptr != NULL)
- wbms = fsp->wbmpx_ptr; /* Use an existing struct */
- else
- wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
- if(!wbms)
- {
- DEBUG(0,("Out of memory in reply_readmpx\n"));
- return(ERROR(ERRSRV,ERRnoresource));
- }
- wbms->wr_mode = write_through;
- wbms->wr_discard = False; /* No errors yet */
- wbms->wr_total_written = nwritten;
- wbms->wr_errclass = 0;
- wbms->wr_error = 0;
- fsp->wbmpx_ptr = wbms;
- }
-
- /* We are returning successfully, set the message type back to
- SMBwritebmpx */
- CVAL(outbuf,smb_com) = SMBwriteBmpx;
-
- outsize = set_message(outbuf,1,0,True);
-
- SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
-
- DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
- fsp->fnum, numtowrite, nwritten ) );
-
- if (write_through && tcount==nwritten) {
- /* we need to send both a primary and a secondary response */
- smb_setlen(outbuf,outsize - 4);
- send_smb(Client,outbuf);
-
- /* now the secondary */
- outsize = set_message(outbuf,1,0,True);
- CVAL(outbuf,smb_com) = SMBwritec;
- SSVAL(outbuf,smb_vwv0,nwritten);
- }
-
- return(outsize);
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
+ char *data;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
+
+ tcount = SVAL(inbuf, smb_vwv1);
+ startpos = IVAL(inbuf, smb_vwv3);
+ write_through = BITSETW(inbuf + smb_vwv7, 0);
+ numtowrite = SVAL(inbuf, smb_vwv10);
+ smb_doff = SVAL(inbuf, smb_vwv11);
+
+ data = smb_base(inbuf) + smb_doff;
+
+ /* If this fails we need to send an SMBwriteC response,
+ not an SMBwritebmpx - set this up now so we don't forget */
+ CVAL(outbuf, smb_com) = SMBwritec;
+
+ if (is_locked(fsp, conn, tcount, startpos, F_WRLCK))
+ return (ERROR(ERRDOS, ERRlock));
+
+ if (seek_file(fsp, startpos) == -1)
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ nwritten = write_file(fsp, data, numtowrite);
+
+ if ((lp_syncalways(SNUM(conn)) || write_through) &&
+ lp_strict_sync(SNUM(conn)))
+ conn->vfs_ops.sync(fsp->fd_ptr->fd);
+
+ if (nwritten < (ssize_t) numtowrite)
+ return (UNIXERROR(ERRHRD, ERRdiskfull));
+
+ /* If the maximum to be written to this file
+ is greater than what we just wrote then set
+ up a secondary struct to be attached to this
+ fd, we will use this to cache error messages etc. */
+ if ((ssize_t) tcount > nwritten)
+ {
+ write_bmpx_struct *wbms;
+ if (fsp->wbmpx_ptr != NULL)
+ wbms = fsp->wbmpx_ptr; /* Use an existing struct */
+ else
+ wbms =
+ (write_bmpx_struct *)
+ malloc(sizeof(write_bmpx_struct));
+ if (!wbms)
+ {
+ DEBUG(0, ("Out of memory in reply_readmpx\n"));
+ return (ERROR(ERRSRV, ERRnoresource));
+ }
+ wbms->wr_mode = write_through;
+ wbms->wr_discard = False; /* No errors yet */
+ wbms->wr_total_written = nwritten;
+ wbms->wr_errclass = 0;
+ wbms->wr_error = 0;
+ fsp->wbmpx_ptr = wbms;
+ }
+
+ /* We are returning successfully, set the message type back to
+ SMBwritebmpx */
+ CVAL(outbuf, smb_com) = SMBwriteBmpx;
+
+ outsize = set_message(outbuf, 1, 0, True);
+
+ SSVALS(outbuf, smb_vwv0, -1); /* We don't support smb_remaining */
+
+ DEBUG(3, ("writebmpx fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, numtowrite, nwritten));
+
+ if (write_through && tcount == nwritten)
+ {
+ /* we need to send both a primary and a secondary response */
+ smb_setlen(outbuf, outsize - 4);
+ send_smb(Client, outbuf);
+
+ /* now the secondary */
+ outsize = set_message(outbuf, 1, 0, True);
+ CVAL(outbuf, smb_com) = SMBwritec;
+ SSVAL(outbuf, smb_vwv0, nwritten);
+ }
+
+ return (outsize);
}
/****************************************************************************
reply to a SMBwritebs (write block multiplex secondary) request
****************************************************************************/
-int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_writebs(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- size_t numtowrite;
- ssize_t nwritten = -1;
- int outsize = 0;
- SMB_OFF_T startpos;
- size_t tcount;
- BOOL write_through;
- int smb_doff;
- char *data;
- write_bmpx_struct *wbms;
- BOOL send_response = False;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- CHECK_FSP(fsp,conn);
- CHECK_WRITE(fsp);
-
- tcount = SVAL(inbuf,smb_vwv1);
- startpos = IVAL(inbuf,smb_vwv2);
- numtowrite = SVAL(inbuf,smb_vwv6);
- smb_doff = SVAL(inbuf,smb_vwv7);
-
- data = smb_base(inbuf) + smb_doff;
-
- /* We need to send an SMBwriteC response, not an SMBwritebs */
- CVAL(outbuf,smb_com) = SMBwritec;
-
- /* This fd should have an auxiliary struct attached,
- check that it does */
- wbms = fsp->wbmpx_ptr;
- if(!wbms) return(-1);
-
- /* If write through is set we can return errors, else we must
- cache them */
- write_through = wbms->wr_mode;
-
- /* Check for an earlier error */
- if(wbms->wr_discard)
- return -1; /* Just discard the packet */
-
- if(seek_file(fsp,startpos) == -1)
- {
- if(write_through)
- {
- /* We are returning an error - we can delete the aux struct */
- if (wbms) free((char *)wbms);
- fsp->wbmpx_ptr = NULL;
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
- return(CACHE_ERROR(wbms,ERRDOS,ERRnoaccess));
- }
-
- nwritten = write_file(fsp,data,numtowrite);
-
- if((lp_syncalways(SNUM(conn)) || write_through) &&
- lp_strict_sync(SNUM(conn)))
- conn->vfs_ops.sync(fsp->fd_ptr->fd);
-
- if (nwritten < (ssize_t)numtowrite)
- {
- if(write_through)
- {
- /* We are returning an error - we can delete the aux struct */
- if (wbms) free((char *)wbms);
- fsp->wbmpx_ptr = NULL;
- return(ERROR(ERRHRD,ERRdiskfull));
- }
- return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
- }
-
- /* Increment the total written, if this matches tcount
- we can discard the auxiliary struct (hurrah !) and return a writeC */
- wbms->wr_total_written += nwritten;
- if(wbms->wr_total_written >= tcount)
- {
- if (write_through)
- {
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
- send_response = True;
- }
-
- free((char *)wbms);
- fsp->wbmpx_ptr = NULL;
- }
-
- if(send_response)
- return(outsize);
-
- return(-1);
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
+ char *data;
+ write_bmpx_struct *wbms;
+ BOOL send_response = False;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_WRITE(fsp);
+
+ tcount = SVAL(inbuf, smb_vwv1);
+ startpos = IVAL(inbuf, smb_vwv2);
+ numtowrite = SVAL(inbuf, smb_vwv6);
+ smb_doff = SVAL(inbuf, smb_vwv7);
+
+ data = smb_base(inbuf) + smb_doff;
+
+ /* We need to send an SMBwriteC response, not an SMBwritebs */
+ CVAL(outbuf, smb_com) = SMBwritec;
+
+ /* This fd should have an auxiliary struct attached,
+ check that it does */
+ wbms = fsp->wbmpx_ptr;
+ if (!wbms)
+ return (-1);
+
+ /* If write through is set we can return errors, else we must
+ cache them */
+ write_through = wbms->wr_mode;
+
+ /* Check for an earlier error */
+ if (wbms->wr_discard)
+ return -1; /* Just discard the packet */
+
+ if (seek_file(fsp, startpos) == -1)
+ {
+ if (write_through)
+ {
+ /* We are returning an error - we can delete the aux struct */
+ if (wbms)
+ free((char *)wbms);
+ fsp->wbmpx_ptr = NULL;
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+ }
+ return (CACHE_ERROR(wbms, ERRDOS, ERRnoaccess));
+ }
+
+ nwritten = write_file(fsp, data, numtowrite);
+
+ if ((lp_syncalways(SNUM(conn)) || write_through) &&
+ lp_strict_sync(SNUM(conn)))
+ conn->vfs_ops.sync(fsp->fd_ptr->fd);
+
+ if (nwritten < (ssize_t) numtowrite)
+ {
+ if (write_through)
+ {
+ /* We are returning an error - we can delete the aux struct */
+ if (wbms)
+ free((char *)wbms);
+ fsp->wbmpx_ptr = NULL;
+ return (ERROR(ERRHRD, ERRdiskfull));
+ }
+ return (CACHE_ERROR(wbms, ERRHRD, ERRdiskfull));
+ }
+
+ /* Increment the total written, if this matches tcount
+ we can discard the auxiliary struct (hurrah !) and return a writeC */
+ wbms->wr_total_written += nwritten;
+ if (wbms->wr_total_written >= tcount)
+ {
+ if (write_through)
+ {
+ outsize = set_message(outbuf, 1, 0, True);
+ SSVAL(outbuf, smb_vwv0, wbms->wr_total_written);
+ send_response = True;
+ }
+
+ free((char *)wbms);
+ fsp->wbmpx_ptr = NULL;
+ }
+
+ if (send_response)
+ return (outsize);
+
+ return (-1);
}
/****************************************************************************
reply to a SMBsetattrE
****************************************************************************/
-int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_setattrE(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- struct utimbuf unix_times;
- int outsize = 0;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- outsize = set_message(outbuf,0,0,True);
-
- CHECK_FSP(fsp,conn);
- CHECK_ERROR(fsp);
-
- /* Convert the DOS times into unix times. Ignore create
- time as UNIX can't set this.
- */
- unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
- unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
-
- /*
- * Patch from Ray Frush <frush@engr.colostate.edu>
- * Sometimes times are sent as zero - ignore them.
- */
-
- if ((unix_times.actime == 0) && (unix_times.modtime == 0))
- {
- /* Ignore request */
- if( DEBUGLVL( 3 ) )
- {
- dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
- dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
- }
- return(outsize);
- }
- else if ((unix_times.actime != 0) && (unix_times.modtime == 0))
- {
- /* set modify time = to access time if modify time was 0 */
- unix_times.modtime = unix_times.actime;
- }
-
- /* Set the date on this file */
- if(file_utime(conn, fsp->fsp_name, &unix_times))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
- fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
-
- return(outsize);
+ struct utimbuf unix_times;
+ int outsize = 0;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ outsize = set_message(outbuf, 0, 0, True);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_ERROR(fsp);
+
+ /* Convert the DOS times into unix times. Ignore create
+ time as UNIX can't set this.
+ */
+ unix_times.actime = make_unix_date2(inbuf + smb_vwv3);
+ unix_times.modtime = make_unix_date2(inbuf + smb_vwv5);
+
+ /*
+ * Patch from Ray Frush <frush@engr.colostate.edu>
+ * Sometimes times are sent as zero - ignore them.
+ */
+
+ if ((unix_times.actime == 0) && (unix_times.modtime == 0))
+ {
+ /* Ignore request */
+ if (DEBUGLVL(3))
+ {
+ dbgtext("reply_setattrE fnum=%d ", fsp->fnum);
+ dbgtext
+ ("ignoring zero request - not setting timestamps of 0\n");
+ }
+ return (outsize);
+ }
+ else if ((unix_times.actime != 0) && (unix_times.modtime == 0))
+ {
+ /* set modify time = to access time if modify time was 0 */
+ unix_times.modtime = unix_times.actime;
+ }
+
+ /* Set the date on this file */
+ if (file_utime(conn, fsp->fsp_name, &unix_times))
+ return (ERROR(ERRDOS, ERRnoaccess));
+
+ DEBUG(3, ("reply_setattrE fnum=%d actime=%d modtime=%d\n",
+ fsp->fnum, (int)unix_times.actime,
+ (int)unix_times.modtime));
+
+ return (outsize);
}
/****************************************************************************
reply to a SMBgetattrE
****************************************************************************/
-int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_getattrE(connection_struct * conn, char *inbuf, char *outbuf,
+ int dum_size, int dum_buffsize)
{
- SMB_STRUCT_STAT sbuf;
- int outsize = 0;
- int mode;
- files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-
- outsize = set_message(outbuf,11,0,True);
-
- CHECK_FSP(fsp,conn);
- CHECK_ERROR(fsp);
-
- /* Do an fstat on this file */
- if(fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd, &sbuf))
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- mode = dos_mode(conn,fsp->fsp_name,&sbuf);
-
- /* Convert the times into dos times. Set create
- date to be last modify date as UNIX doesn't save
- this */
- put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
- put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
- put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
- if (mode & aDIR)
- {
- SIVAL(outbuf,smb_vwv6,0);
- SIVAL(outbuf,smb_vwv8,0);
- }
- else
- {
- SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
- SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
- }
- SSVAL(outbuf,smb_vwv10, mode);
-
- DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
-
- return(outsize);
+ SMB_STRUCT_STAT sbuf;
+ int outsize = 0;
+ int mode;
+ files_struct *fsp = file_fsp(inbuf, smb_vwv0);
+
+ outsize = set_message(outbuf, 11, 0, True);
+
+ CHECK_FSP(fsp, conn);
+ CHECK_ERROR(fsp);
+
+ /* Do an fstat on this file */
+ if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd, &sbuf))
+ return (UNIXERROR(ERRDOS, ERRnoaccess));
+
+ mode = dos_mode(conn, fsp->fsp_name, &sbuf);
+
+ /* Convert the times into dos times. Set create
+ date to be last modify date as UNIX doesn't save
+ this */
+ put_dos_date2(outbuf, smb_vwv0,
+ get_create_time(&sbuf,
+ lp_fake_dir_create_times(SNUM(conn))));
+ put_dos_date2(outbuf, smb_vwv2, sbuf.st_atime);
+ put_dos_date2(outbuf, smb_vwv4, sbuf.st_mtime);
+ if (mode & aDIR)
+ {
+ SIVAL(outbuf, smb_vwv6, 0);
+ SIVAL(outbuf, smb_vwv8, 0);
+ }
+ else
+ {
+ SIVAL(outbuf, smb_vwv6, (uint32) sbuf.st_size);
+ SIVAL(outbuf, smb_vwv8, SMB_ROUNDUP(sbuf.st_size, 1024));
+ }
+ SSVAL(outbuf, smb_vwv10, mode);
+
+ DEBUG(3, ("reply_getattrE fnum=%d\n", fsp->fnum));
+
+ return (outsize);
}