summaryrefslogtreecommitdiff
path: root/source/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source/smbd')
-rw-r--r--source/smbd/chgpasswd.c40
-rw-r--r--source/smbd/connection.c5
-rw-r--r--source/smbd/dosmode.c12
-rw-r--r--source/smbd/fileio.c16
-rw-r--r--source/smbd/ipc.c4
-rw-r--r--source/smbd/lanman.c108
-rw-r--r--source/smbd/negprot.c8
-rw-r--r--source/smbd/nttrans.c47
-rw-r--r--source/smbd/open.c8
-rw-r--r--source/smbd/pipes.c2
-rw-r--r--source/smbd/posix_acls.c410
-rw-r--r--source/smbd/process.c3
-rw-r--r--source/smbd/quotas.c4
-rw-r--r--source/smbd/reply.c152
-rw-r--r--source/smbd/server.c17
-rw-r--r--source/smbd/service.c16
-rw-r--r--source/smbd/sesssetup.c2
-rw-r--r--source/smbd/trans2.c404
-rw-r--r--source/smbd/vfs-wrap.c33
-rw-r--r--source/smbd/vfs.c10
20 files changed, 1032 insertions, 269 deletions
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index c91f8599c96..540acfc2250 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -753,9 +753,8 @@ static NTSTATUS check_oem_password(const char *user,
uint16 acct_ctrl;
uint32 new_pw_len;
uchar new_nt_hash[16];
- uchar old_nt_hash_plain[16];
uchar new_lm_hash[16];
- uchar old_lm_hash_plain[16];
+ uchar verifier[16];
char no_pw[2];
BOOL ret;
@@ -784,7 +783,7 @@ static NTSTATUS check_oem_password(const char *user,
return NT_STATUS_ACCOUNT_DISABLED;
}
- if (acct_ctrl & ACB_PWNOTREQ && lp_null_passwords()) {
+ if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
/* construct a null password (in case one is needed */
no_pw[0] = 0;
no_pw[1] = 0;
@@ -818,9 +817,14 @@ static NTSTATUS check_oem_password(const char *user,
pdb_free_sam(&sampass);
return NT_STATUS_WRONG_PASSWORD;
} else if (lm_pass_set) {
- DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
- user));
- pdb_free_sam(&sampass);
+ if (lp_lanman_auth()) {
+ DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
+ user));
+ } else {
+ DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
+ user));
+ }
+ pdb_free_sam(&sampass);
return NT_STATUS_WRONG_PASSWORD;
} else {
DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
@@ -854,12 +858,10 @@ static NTSTATUS check_oem_password(const char *user,
if (nt_pw) {
/*
- * Now use new_nt_hash as the key to see if the old
- * password matches.
+ * check the NT verifier
*/
- D_P16(new_nt_hash, old_nt_hash_encrypted, old_nt_hash_plain);
-
- if (memcmp(nt_pw, old_nt_hash_plain, 16)) {
+ E_old_pw_hash(new_nt_hash, nt_pw, verifier);
+ if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
pdb_free_sam(&sampass);
return NT_STATUS_WRONG_PASSWORD;
@@ -884,12 +886,10 @@ static NTSTATUS check_oem_password(const char *user,
if (lanman_pw) {
/*
- * Now use new_nt_hash as the key to see if the old
- * LM password matches.
+ * check the lm verifier
*/
- D_P16(new_nt_hash, old_lm_hash_encrypted, old_lm_hash_plain);
-
- if (memcmp(lanman_pw, old_lm_hash_plain, 16)) {
+ E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
+ if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
pdb_free_sam(&sampass);
return NT_STATUS_WRONG_PASSWORD;
@@ -908,12 +908,10 @@ static NTSTATUS check_oem_password(const char *user,
E_deshash(new_passwd, new_lm_hash);
/*
- * Now use new_lm_hash as the key to see if the old
- * password matches.
+ * check the lm verifier
*/
- D_P16(new_lm_hash, old_lm_hash_encrypted, old_lm_hash_plain);
-
- if (memcmp(lanman_pw, old_lm_hash_plain, 16)) {
+ E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
+ if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
pdb_free_sam(&sampass);
return NT_STATUS_WRONG_PASSWORD;
diff --git a/source/smbd/connection.c b/source/smbd/connection.c
index fc5fe9d7418..32e2f058fc2 100644
--- a/source/smbd/connection.c
+++ b/source/smbd/connection.c
@@ -217,7 +217,8 @@ BOOL register_message_flags(BOOL doreg, uint32 msg_flags)
dbuf = tdb_fetch(tdb, kbuf);
if (!dbuf.dptr) {
- DEBUG(0,("register_message_flags: tdb_fetch failed\n"));
+ DEBUG(0,("register_message_flags: tdb_fetch failed: %s\n",
+ tdb_errorstr(tdb)));
return False;
}
@@ -228,7 +229,7 @@ BOOL register_message_flags(BOOL doreg, uint32 msg_flags)
pcrec->bcast_msg_flags &= ~msg_flags;
if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
- DEBUG(0,("register_message_flags: tdb_store failed with error %s.\n",
+ DEBUG(0,("register_message_flags: tdb_store failed: %s.\n",
tdb_errorstr(tdb) ));
SAFE_FREE(dbuf.dptr);
return False;
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
index 7199b3ebbf3..fefcaca09d5 100644
--- a/source/smbd/dosmode.c
+++ b/source/smbd/dosmode.c
@@ -23,7 +23,7 @@
/****************************************************************************
Change a dos mode to a unix mode.
Base permission for files:
- if inheriting
+ if creating file and inheriting
apply read/write bits from parent directory.
else
everybody gets read bit set
@@ -43,7 +43,7 @@
}
****************************************************************************/
-mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname)
+mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname, BOOL creating_file)
{
mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */
@@ -52,7 +52,7 @@ mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname)
result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
}
- if (fname && lp_inherit_perms(SNUM(conn))) {
+ if (fname && creating_file && lp_inherit_perms(SNUM(conn))) {
char *dname;
SMB_STRUCT_STAT sbuf;
@@ -329,7 +329,7 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
chmod a file - but preserve some bits.
********************************************************************/
-int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode, SMB_STRUCT_STAT *st)
+int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode, SMB_STRUCT_STAT *st, BOOL creating_file)
{
SMB_STRUCT_STAT st1;
int mask=0;
@@ -338,7 +338,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode,
int ret = -1;
DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
- if (!st) {
+ if (!st || (st && !VALID_STAT(*st))) {
st = &st1;
if (SMB_VFS_STAT(conn,fname,st))
return(-1);
@@ -359,7 +359,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode,
return 0;
}
- unixmode = unix_mode(conn,dosmode,fname);
+ unixmode = unix_mode(conn,dosmode,fname, creating_file);
/* preserve the s bits */
mask |= (S_ISUID | S_ISGID);
diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c
index bc62683eaee..a21bd69a36c 100644
--- a/source/smbd/fileio.c
+++ b/source/smbd/fileio.c
@@ -130,6 +130,20 @@ static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_
if (ret != -1) {
fsp->pos += ret;
+ /*
+ * It turns out that setting the last write time from a Windows
+ * client stops any subsequent writes from updating the write time.
+ * Doing this after the write gives a race condition here where
+ * a stat may see the changed write time before we reset it here,
+ * but it's cheaper than having to store the write time in shared
+ * memory and look it up using dev/inode across all running smbd's.
+ * The 99% solution will hopefully be good enough in this case. JRA.
+ */
+
+ if (fsp->pending_modtime) {
+ set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime);
+ }
+
/* Yes - this is correct - writes don't update this. JRA. */
/* Found by Samba4 tests. */
#if 0
@@ -177,7 +191,7 @@ ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
fsp->size = (SMB_BIG_UINT)st.st_size;
if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) {
- file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st);
+ file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False);
}
/*
diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c
index ec8176e1234..9fcd39b5002 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -502,7 +502,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
goto bad_param;
if (pcnt) {
- if (pdisp+pcnt >= tpscnt)
+ if (pdisp+pcnt > tpscnt)
goto bad_param;
if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
goto bad_param;
@@ -518,7 +518,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
}
if (dcnt) {
- if (ddisp+dcnt >= tdscnt)
+ if (ddisp+dcnt > tdscnt)
goto bad_param;
if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
goto bad_param;
diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c
index f4dad2ddb9c..4af11da7844 100644
--- a/source/smbd/lanman.c
+++ b/source/smbd/lanman.c
@@ -760,18 +760,10 @@ static BOOL api_DosPrintQGetInfo(connection_struct *conn,
return(True);
}
- snum = lp_servicenumber(QueueName);
- if (snum < 0 && pcap_printername_ok(QueueName,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(QueueName,pnum);
- snum = lp_servicenumber(QueueName);
- }
- }
-
- if (snum < 0 || !VALID_SNUM(snum))
- return(False);
-
+ snum = find_service(QueueName);
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
+ return False;
+
if (uLevel==52) {
count = get_printerdrivernumber(snum);
DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
@@ -1501,6 +1493,8 @@ static BOOL api_RNetShareEnum( connection_struct *conn,
data_len = fixed_len = string_len = 0;
for (i=0;i<count;i++) {
fstring servicename_dos;
+ if (!(lp_browseable(i) && lp_snum_ok(i)))
+ continue;
push_ascii_fstring(servicename_dos, lp_servicename(i));
if( lp_browseable( i )
&& lp_snum_ok( i )
@@ -1529,6 +1523,8 @@ static BOOL api_RNetShareEnum( connection_struct *conn,
for( i = 0; i < count; i++ )
{
fstring servicename_dos;
+ if (!(lp_browseable(i) && lp_snum_ok(i)))
+ continue;
push_ascii_fstring(servicename_dos, lp_servicename(i));
if( lp_browseable( i )
&& lp_snum_ok( i )
@@ -1740,13 +1736,15 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para
int count=0;
SAM_ACCOUNT *sampw = NULL;
BOOL ret = False;
- DOM_GID *gids = NULL;
- int num_groups = 0;
+ DOM_SID *sids;
+ gid_t *gids;
+ int num_groups;
int i;
fstring grp_domain;
fstring grp_name;
enum SID_NAME_USE grp_type;
- DOM_SID sid, dom_sid;
+ struct passwd *passwd;
+ NTSTATUS result;
*rparam_len = 8;
*rparam = SMB_REALLOC_LIMIT(*rparam,*rparam_len);
@@ -1777,6 +1775,11 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para
/* Lookup the user information; This should only be one of
our accounts (not remote domains) */
+
+ passwd = getpwnam_alloc(UserName);
+
+ if (passwd == NULL)
+ return False;
pdb_init_sam( &sampw );
@@ -1785,35 +1788,26 @@ static BOOL api_NetUserGetGroups(connection_struct *conn,uint16 vuid, char *para
if ( !pdb_getsampwnam(sampw, UserName) )
goto out;
- /* this next set of code is horribly inefficient, but since
- it is rarely called, I'm going to leave it like this since
- it easier to follow --jerry */
-
- /* get the list of group SIDs */
-
- if ( !get_domain_user_groups(conn->mem_ctx, &num_groups, &gids, sampw) ) {
- DEBUG(1,("api_NetUserGetGroups: get_domain_user_groups() failed!\n"));
+ sids = NULL;
+ num_groups = 0;
+
+ result = pdb_enum_group_memberships(pdb_get_username(sampw),
+ passwd->pw_gid,
+ &sids, &gids, &num_groups);
+
+ if (!NT_STATUS_IS_OK(result))
goto out;
- }
- /* convert to names (we don't support universal groups so the domain
- can only be ours) */
-
- sid_copy( &dom_sid, get_global_sam_sid() );
for (i=0; i<num_groups; i++) {
- /* make the DOM_GID into a DOM_SID and then lookup
- the name */
-
- sid_copy( &sid, &dom_sid );
- sid_append_rid( &sid, gids[i].g_rid );
-
- if ( lookup_sid(&sid, grp_domain, grp_name, &grp_type) ) {
+ if ( lookup_sid(&sids[i], grp_domain, grp_name, &grp_type) ) {
pstrcpy(p, grp_name);
p += 21;
count++;
}
}
+
+ SAFE_FREE(sids);
*rdata_len = PTR_DIFF(p,*rdata);
@@ -1826,6 +1820,7 @@ out:
unbecome_root(); /* END ROOT BLOCK */
pdb_free_sam( &sampw );
+ passwd_free(&passwd);
return ret;
}
@@ -2142,6 +2137,12 @@ static BOOL api_RDosPrintJobDel(connection_struct *conn,uint16 vuid, char *param
goto out;
}
+ snum = lp_servicenumber( sharename);
+ if (snum == -1) {
+ errcode = NERR_DestNotFound;
+ goto out;
+ }
+
errcode = NERR_notsupported;
switch (function) {
@@ -2967,6 +2968,7 @@ static BOOL api_WPrintJobGetInfo(connection_struct *conn,uint16 vuid, char *para
if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid))
return False;
+ snum = lp_servicenumber( sharename);
if (snum < 0 || !VALID_SNUM(snum)) return(False);
count = print_queue_status(snum,&queue,&status);
@@ -3037,20 +3039,18 @@ static BOOL api_WPrintJobEnumerate(connection_struct *conn,uint16 vuid, char *pa
DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
/* check it's a supported variant */
- if (strcmp(str1,"zWrLeh") != 0) return False;
- if (uLevel > 2) return False; /* defined only for uLevel 0,1,2 */
- if (!check_printjob_info(&desc,uLevel,str2)) return False;
-
- snum = lp_servicenumber(name);
- if (snum < 0 && pcap_printername_ok(name,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(name,pnum);
- snum = lp_servicenumber(name);
- }
- }
+ if (strcmp(str1,"zWrLeh") != 0)
+ return False;
+
+ if (uLevel > 2)
+ return False; /* defined only for uLevel 0,1,2 */
+
+ if (!check_printjob_info(&desc,uLevel,str2))
+ return False;
- if (snum < 0 || !VALID_SNUM(snum)) return(False);
+ snum = find_service(name);
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) )
+ return False;
count = print_queue_status(snum,&queue,&status);
if (mdrcnt > 0) *rdata = SMB_REALLOC_LIMIT(*rdata,mdrcnt);
@@ -3153,16 +3153,8 @@ static BOOL api_WPrintDestGetInfo(connection_struct *conn,uint16 vuid, char *par
if (strcmp(str1,"zWrLh") != 0) return False;
if (!check_printdest_info(&desc,uLevel,str2)) return False;
- snum = lp_servicenumber(PrinterName);
- if (snum < 0 && pcap_printername_ok(PrinterName,NULL)) {
- int pnum = lp_servicenumber(PRINTERS_NAME);
- if (pnum >= 0) {
- lp_add_printer(PrinterName,pnum);
- snum = lp_servicenumber(PrinterName);
- }
- }
-
- if (snum < 0) {
+ snum = find_service(PrinterName);
+ if ( !(lp_snum_ok(snum) && lp_print_ok(snum)) ) {
*rdata_len = 0;
desc.errcode = NERR_DestNotFound;
desc.neededlen = 0;
diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c
index 447073acd84..9aaa818c62a 100644
--- a/source/smbd/negprot.c
+++ b/source/smbd/negprot.c
@@ -20,7 +20,7 @@
#include "includes.h"
-extern int Protocol;
+extern enum protocol_types Protocol;
extern int max_recv;
BOOL global_encrypted_passwords_negotiated = False;
BOOL global_spnego_negotiated = False;
@@ -523,6 +523,12 @@ int reply_negprot(connection_struct *conn,
/* possibly reload - change of architecture */
reload_services(True);
+
+ /* moved from the netbios session setup code since we don't have that
+ when the client connects to port 445. Of course there is a small
+ window where we are listening to messages -- jerry */
+
+ claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
/* Check for protocols, most desirable first */
for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index 755b5abb160..2395d0d8db5 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -21,7 +21,7 @@
#include "includes.h"
-extern int Protocol;
+extern enum protocol_types Protocol;
extern int smb_read_error;
extern int global_oplock_break;
extern struct current_user current_user;
@@ -1144,7 +1144,7 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu
static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
char **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
pstring fname;
char *params = *ppparams;
@@ -1662,7 +1662,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
/* Grrr. We have to do this as open_file_shared1 adds aARCH when it
creates the file. This isn't the correct thing to do in the copy case. JRA */
- file_set_dosmode(conn, newname, fmode, &sbuf2);
+ file_set_dosmode(conn, newname, fmode, &sbuf2, True);
if (ret < (SMB_OFF_T)sbuf1.st_size) {
return NT_STATUS_DISK_FULL;
@@ -1783,7 +1783,7 @@ int reply_nttranss(connection_struct *conn,
static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
char **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *setup = *ppsetup;
files_struct *fsp;
@@ -1819,7 +1819,7 @@ name = %s\n", fsp->fsp_name ));
static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
char **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *params = *ppparams;
pstring new_name;
@@ -1886,9 +1886,8 @@ static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd)
static int call_nt_transact_query_security_desc(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
char **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
char *params = *ppparams;
char *data = *ppdata;
prs_struct pd;
@@ -1998,7 +1997,7 @@ security descriptor.\n"));
static int call_nt_transact_set_security_desc(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
char **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *params= *ppparams;
char *data = *ppdata;
@@ -2039,7 +2038,7 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, char *inb
static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
char **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
uint32 function;
uint16 fidnum;
@@ -2116,7 +2115,6 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
* Allocate the correct amount and return the pointer to let
* it be deallocated when we return.
*/
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
SHADOW_COPY_DATA *shadow_data = NULL;
TALLOC_CTX *shadow_mem_ctx = NULL;
BOOL labels = False;
@@ -2289,10 +2287,9 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
char **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
NTSTATUS nt_status = NT_STATUS_OK;
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
char *params = *ppparams;
char *pdata = *ppdata;
char *entry;
@@ -2543,7 +2540,7 @@ static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf,
static int call_nt_transact_set_user_quota(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
char **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *params = *ppparams;
char *pdata = *ppdata;
@@ -2662,10 +2659,10 @@ int reply_nttrans(connection_struct *conn,
char *inbuf,char *outbuf,int length,int bufsize)
{
int outsize = 0;
+ uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
#if 0 /* Not used. */
uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount);
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
#endif /* Not used. */
uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount);
uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount);
@@ -2711,7 +2708,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
goto bad_param;
}
-
+
/* Don't allow more than 128mb for each value. */
if ((total_parameter_count > (1024*1024*128)) || (total_data_count > (1024*1024*128))) {
END_PROFILE(SMBnttrans);
@@ -2836,7 +2833,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
}
if (parameter_count) {
- if (parameter_displacement + parameter_count >= total_parameter_count)
+ if (parameter_displacement + parameter_count > total_parameter_count)
goto bad_param;
if ((parameter_displacement + parameter_count < parameter_displacement) ||
(parameter_displacement + parameter_count < parameter_count))
@@ -2853,7 +2850,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
}
if (data_count) {
- if (data_displacement + data_count >= total_data_count)
+ if (data_displacement + data_count > total_data_count)
goto bad_param;
if ((data_displacement + data_count < data_displacement) ||
(data_displacement + data_count < data_count))
@@ -2882,7 +2879,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
length, bufsize,
&setup, setup_count,
&params, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_create);
break;
case NT_TRANSACT_IOCTL:
@@ -2891,7 +2888,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
length, bufsize,
&setup, setup_count,
&params, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_ioctl);
break;
case NT_TRANSACT_SET_SECURITY_DESC:
@@ -2900,7 +2897,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
length, bufsize,
&setup, setup_count,
&params, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_set_security_desc);
break;
case NT_TRANSACT_NOTIFY_CHANGE:
@@ -2909,7 +2906,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
length, bufsize,
&setup, setup_count,
&params, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_notify_change);
break;
case NT_TRANSACT_RENAME:
@@ -2918,7 +2915,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
length, bufsize,
&setup, setup_count,
&params, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_rename);
break;
@@ -2928,7 +2925,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
length, bufsize,
&setup, setup_count,
&params, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_query_security_desc);
break;
#ifdef HAVE_SYS_QUOTAS
@@ -2938,7 +2935,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
length, bufsize,
&setup, setup_count,
&params, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_get_user_quota);
break;
case NT_TRANSACT_SET_USER_QUOTA:
@@ -2947,7 +2944,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
length, bufsize,
&setup, setup_count,
&params, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_set_user_quota);
break;
#endif /* HAVE_SYS_QUOTAS */
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 278c195f10f..bf3fbf7fecd 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -979,7 +979,7 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
struct pending_message_list *pml = NULL;
uint16 mid = get_current_mid();
/* We add aARCH to this as this mode is only used if the file is created new. */
- mode_t mode = unix_mode(conn,new_dos_mode | aARCH,fname);
+ mode_t mode = unix_mode(conn,new_dos_mode | aARCH,fname, True);
if (oplock_request == INTERNAL_OPEN_ONLY) {
internal_only_open = True;
@@ -1376,6 +1376,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
(*Access) = open_mode;
}
+ action = 0;
+
if (file_existed && !(flags2 & O_TRUNC))
action = FILE_WAS_OPENED;
if (file_existed && (flags2 & O_TRUNC))
@@ -1438,7 +1440,7 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
if (action == FILE_WAS_OVERWRITTEN || action == FILE_WAS_CREATED) {
/* Files should be initially set as archive */
if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) {
- file_set_dosmode(conn, fname, new_dos_mode | aARCH, NULL);
+ file_set_dosmode(conn, fname, new_dos_mode | aARCH, NULL, True);
}
}
@@ -1599,7 +1601,7 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST
return NULL;
}
- if(vfs_MkDir(conn,fname, unix_mode(conn,aDIR, fname)) < 0) {
+ if(vfs_MkDir(conn,fname, unix_mode(conn,aDIR, fname, True)) < 0) {
DEBUG(2,("open_directory: unable to create %s. Error was %s\n",
fname, strerror(errno) ));
file_free(fsp);
diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c
index f7e9c595c13..6c7faa4c056 100644
--- a/source/smbd/pipes.c
+++ b/source/smbd/pipes.c
@@ -241,6 +241,8 @@ int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
DEBUG(3,("readX-IPC pnum=%04x min=%d max=%d nread=%d\n",
p->pnum, smb_mincnt, smb_maxcnt, nread));
+ /* Ensure we set up the message length to include the data length read. */
+ set_message_bcc(outbuf,nread);
return chain_reply(inbuf,outbuf,length,bufsize);
}
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
index 321d5e20ab4..903b9435225 100644
--- a/source/smbd/posix_acls.c
+++ b/source/smbd/posix_acls.c
@@ -1867,7 +1867,7 @@ static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
int snum = SNUM(fsp->conn);
mode_t and_bits = (mode_t)0;
mode_t or_bits = (mode_t)0;
- mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name) : S_IRUSR;
+ mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name, False) : S_IRUSR;
if (fsp->is_directory)
mode |= (S_IWUSR|S_IXUSR);
@@ -2641,10 +2641,10 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
size_t sd_size = 0;
SEC_ACL *psa = NULL;
size_t num_acls = 0;
- size_t num_dir_acls = 0;
+ size_t num_def_acls = 0;
size_t num_aces = 0;
SMB_ACL_T posix_acl = NULL;
- SMB_ACL_T dir_acl = NULL;
+ SMB_ACL_T def_acl = NULL;
canon_ace *file_ace = NULL;
canon_ace *dir_ace = NULL;
size_t num_profile_acls = 0;
@@ -2672,8 +2672,8 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
*/
if(fsp->is_directory) {
- dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
- dir_acl = free_empty_sys_acl(conn, dir_acl);
+ def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
+ def_acl = free_empty_sys_acl(conn, def_acl);
}
} else {
@@ -2690,7 +2690,7 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
posix_acl ? "present" : "absent",
- dir_acl ? "present" : "absent" ));
+ def_acl ? "present" : "absent" ));
pal = load_inherited_info(fsp);
@@ -2728,8 +2728,8 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
return 0;
}
- if (fsp->is_directory && dir_acl) {
- dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
+ if (fsp->is_directory && def_acl) {
+ dir_ace = canonicalise_acl(fsp, def_acl, &sbuf,
&global_sid_Creator_Owner,
&global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
}
@@ -2793,15 +2793,15 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
}
num_acls = count_canon_ace_list(file_ace);
- num_dir_acls = count_canon_ace_list(dir_ace);
+ num_def_acls = count_canon_ace_list(dir_ace);
/* Allocate the ace list. */
- if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE, num_acls + num_profile_acls + num_dir_acls)) == NULL) {
+ if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
goto done;
}
- memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
+ memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
/*
* Create the NT ACE list from the canonical ace lists.
@@ -2827,7 +2827,7 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
ace = dir_ace;
- for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
+ for (i = 0; i < num_def_acls; i++, ace = ace->next) {
SEC_ACCESS acc;
acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
@@ -2883,9 +2883,11 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
* inherited at file create time, so ACLs never contain
* any ACEs that are inherited dynamically. The DACL_PROTECTED
* flag doesn't seem to bother Windows NT.
+ * Always set this if map acl inherit is turned off.
*/
- if (get_protected_flag(pal))
+ if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) {
psd->type |= SE_DESC_DACL_PROTECTED;
+ }
}
if (psd->dacl)
@@ -2897,8 +2899,8 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
if (posix_acl)
SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
- if (dir_acl)
- SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
+ if (def_acl)
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
free_inherited_info(pal);
@@ -3376,14 +3378,378 @@ int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
{
- SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
- BOOL has_acl = False;
- SMB_ACL_ENTRY_T entry;
+ SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
+ BOOL has_acl = False;
+ SMB_ACL_ENTRY_T entry;
- if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
- has_acl = True;
+ if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
+ has_acl = True;
+ }
- if (dir_acl)
- SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
return has_acl;
}
+
+/****************************************************************************
+ Map from wire type to permset.
+****************************************************************************/
+
+static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
+{
+ if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
+ return False;
+ }
+
+ if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1) {
+ return False;
+ }
+
+ if (wire_perm & SMB_POSIX_ACL_READ) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
+ return False;
+ }
+ }
+ if (wire_perm & SMB_POSIX_ACL_WRITE) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
+ return False;
+ }
+ }
+ if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
+ if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
+ return False;
+ }
+ }
+ return True;
+}
+
+/****************************************************************************
+ Map from wire type to tagtype.
+****************************************************************************/
+
+static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
+{
+ switch (wire_tt) {
+ case SMB_POSIX_ACL_USER_OBJ:
+ *p_tt = SMB_ACL_USER_OBJ;
+ break;
+ case SMB_POSIX_ACL_USER:
+ *p_tt = SMB_ACL_USER;
+ break;
+ case SMB_POSIX_ACL_GROUP_OBJ:
+ *p_tt = SMB_ACL_GROUP_OBJ;
+ break;
+ case SMB_POSIX_ACL_GROUP:
+ *p_tt = SMB_ACL_GROUP;
+ break;
+ case SMB_POSIX_ACL_MASK:
+ *p_tt = SMB_ACL_MASK;
+ break;
+ case SMB_POSIX_ACL_OTHER:
+ *p_tt = SMB_ACL_OTHER;
+ break;
+ default:
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Create a new POSIX acl from wire permissions.
+ FIXME ! How does the share mask/mode fit into this.... ?
+****************************************************************************/
+
+static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
+{
+ unsigned int i;
+ SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
+
+ if (the_acl == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < num_acls; i++) {
+ SMB_ACL_ENTRY_T the_entry;
+ SMB_ACL_PERMSET_T the_permset;
+ SMB_ACL_TAG_T tag_type;
+
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
+ DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
+ CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
+ goto fail;
+ }
+
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ /* Get the permset pointer from the new ACL entry. */
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ /* Map from wire to permissions. */
+ if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
+ DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
+ CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
+ goto fail;
+ }
+
+ /* Now apply to the new ACL entry. */
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
+ i, strerror(errno) ));
+ goto fail;
+ }
+
+ if (tag_type == SMB_ACL_USER) {
+ uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+ uid_t uid = (uid_t)uidval;
+ if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
+ (unsigned int)uid, i, strerror(errno) ));
+ goto fail;
+ }
+ }
+
+ if (tag_type == SMB_ACL_GROUP) {
+ uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+ gid_t gid = (uid_t)gidval;
+ if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
+ DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
+ (unsigned int)gid, i, strerror(errno) ));
+ goto fail;
+ }
+ }
+ }
+
+ return the_acl;
+
+ fail:
+
+ if (the_acl != NULL) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Calls from UNIX extensions - Default POSIX ACL set.
+ If num_def_acls == 0 and not a directory just return. If it is a directory
+ and num_def_acls == 0 then remove the default acl. Else set the default acl
+ on the directory.
+****************************************************************************/
+
+BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
+ uint16 num_def_acls, const char *pdata)
+{
+ SMB_ACL_T def_acl = NULL;
+
+ if (num_def_acls && !S_ISDIR(psbuf->st_mode)) {
+ DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
+ errno = EISDIR;
+ return False;
+ }
+
+ if (!num_def_acls) {
+ /* Remove the default ACL. */
+ if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
+ DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
+ fname, strerror(errno) ));
+ return False;
+ }
+ return True;
+ }
+
+ if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
+ return False;
+ }
+
+ if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
+ DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
+ fname, strerror(errno) ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ return False;
+ }
+
+ DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ return True;
+}
+
+/****************************************************************************
+ Remove an ACL from a file. As we don't have acl_delete_entry() available
+ we must read the current acl and copy all entries except MASK, USER and GROUP
+ to a new acl, then set that. This (at least on Linux) causes any ACL to be
+ removed.
+ FIXME ! How does the share mask/mode fit into this.... ?
+****************************************************************************/
+
+static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
+{
+ SMB_ACL_T file_acl = NULL;
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+ BOOL ret = False;
+ /* Create a new ACL with only 3 entries, u/g/w. */
+ SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
+ SMB_ACL_ENTRY_T user_ent = NULL;
+ SMB_ACL_ENTRY_T group_ent = NULL;
+ SMB_ACL_ENTRY_T other_ent = NULL;
+
+ if (new_file_acl == NULL) {
+ DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
+ return False;
+ }
+
+ /* Now create the u/g/w entries. */
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+ if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
+ DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ /* Get the current file ACL. */
+ if (fsp && fsp->fd != -1) {
+ file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
+ } else {
+ file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
+ }
+
+ if (file_acl == NULL) {
+ /* This is only returned if an error occurred. Even for a file with
+ no acl a u/g/w acl should be returned. */
+ DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+
+ /* get_next... */
+ if (entry_id == SMB_ACL_FIRST_ENTRY)
+ entry_id = SMB_ACL_NEXT_ENTRY;
+
+ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ goto done;
+ }
+
+ if (tagtype == SMB_ACL_USER_OBJ) {
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ }
+ } else if (tagtype == SMB_ACL_GROUP_OBJ) {
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ }
+ } else if (tagtype == SMB_ACL_OTHER) {
+ if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
+ DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
+ fname, strerror(errno) ));
+ }
+ }
+ }
+
+ ret = True;
+
+ done:
+
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (new_file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ Calls from UNIX extensions - POSIX ACL set.
+ If num_def_acls == 0 then read/modify/write acl after removing all entries
+ except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
+****************************************************************************/
+
+BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
+{
+ SMB_ACL_T file_acl = NULL;
+
+ if (!num_acls) {
+ /* Remove the ACL from the file. */
+ return remove_posix_acl(conn, fsp, fname);
+ }
+
+ if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
+ return False;
+ }
+
+ if (fsp && fsp->fd != -1) {
+ /* The preferred way - use an open fd. */
+ if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, file_acl) == -1) {
+ DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
+ fname, strerror(errno) ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ return False;
+ }
+ } else {
+ if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
+ DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
+ fname, strerror(errno) ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ return False;
+ }
+ }
+
+ DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ return True;
+}
diff --git a/source/smbd/process.c b/source/smbd/process.c
index 8adc5c2e665..1372ebbf458 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -1177,8 +1177,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
int outsize2;
char inbuf_saved[smb_wct];
char outbuf_saved[smb_wct];
- int wct = CVAL(outbuf,smb_wct);
- int outsize = smb_size + 2*wct + SVAL(outbuf,smb_vwv0+2*wct);
+ int outsize = smb_len(outbuf) + 4;
/* maybe its not chained */
if (smb_com2 == 0xFF) {
diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c
index 3c4d4319f63..a96f50ad02f 100644
--- a/source/smbd/quotas.c
+++ b/source/smbd/quotas.c
@@ -471,7 +471,7 @@ static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_B
len=strcspn(mnttype, ":");
pathname=strstr(mnttype, ":");
- cutstr = (char *) malloc(len+1);
+ cutstr = (char *) SMB_MALLOC(len+1);
if (!cutstr)
return False;
@@ -1000,7 +1000,7 @@ static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_B
len=strcspn(mnttype, ":");
pathname=strstr(mnttype, ":");
- cutstr = (char *) malloc(len+1);
+ cutstr = (char *) SMB_MALLOC(len+1);
if (!cutstr)
return False;
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 6135c36580b..26a0c9e7a9b 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -27,12 +27,13 @@
#include "includes.h"
/* look in server.c for some explanation of these variables */
-extern int Protocol;
+extern enum protocol_types Protocol;
extern int max_send;
extern int max_recv;
extern char magic_char;
extern int global_oplock_break;
unsigned int smb_echo_count = 0;
+extern uint32 global_client_caps;
extern BOOL global_encrypted_passwords_negotiated;
@@ -258,8 +259,6 @@ int reply_special(char *inbuf,char *outbuf)
reload_services(True);
reopen_logs();
- claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
-
already_got_session = True;
break;
@@ -718,7 +717,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
mode &= ~aDIR;
if (check_name(fname,conn)) {
- ok = (file_set_dosmode(conn,fname,mode,NULL) == 0);
+ ok = (file_set_dosmode(conn,fname,mode,&sbuf,False) == 0);
}
} else {
ok = True;
@@ -1716,7 +1715,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
Fail for readbraw.
****************************************************************************/
-void fail_readraw(void)
+static void fail_readraw(void)
{
pstring errstr;
slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
@@ -1724,12 +1723,46 @@ void fail_readraw(void)
exit_server(errstr);
}
+#if defined(WITH_SENDFILE)
+/****************************************************************************
+ Fake (read/write) sendfile. Returns -1 on read or write fail.
+****************************************************************************/
+
+static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, int bufsize)
+{
+ ssize_t ret=0;
+
+ /* Paranioa check... */
+ if (nread > bufsize) {
+ fail_readraw();
+ }
+
+ if (nread > 0) {
+ ret = read_file(fsp,buf,startpos,nread);
+ if (ret == -1) {
+ return -1;
+ }
+ }
+
+ /* If we had a short read, fill with zeros. */
+ if (ret < nread) {
+ memset(buf, '\0', nread - ret);
+ }
+
+ if (write_data(smbd_server_fd(),buf,nread) != nread) {
+ return -1;
+ }
+
+ return (ssize_t)nread;
+}
+#endif
+
/****************************************************************************
Use sendfile in readbraw.
****************************************************************************/
void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread,
- ssize_t mincount, char *outbuf)
+ ssize_t mincount, char *outbuf, int out_buffsize)
{
ssize_t ret=0;
@@ -1750,13 +1783,27 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
header.free = NULL;
if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) {
+ /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
+ if (errno == ENOSYS) {
+ goto normal_readbraw;
+ }
+
/*
- * Special hack for broken Linux with no 64 bit clean sendfile. If we
- * return ENOSYS then pretend we just got a normal read.
+ * Special hack for broken Linux with no working sendfile. If we
+ * return EINTR we sent the header but not the rest of the data.
+ * Fake this up by doing read/write calls.
*/
- if (errno == ENOSYS) {
+ if (errno == EINTR) {
+ /* Ensure we don't do this again. */
set_use_sendfile(SNUM(conn), False);
- goto normal_read;
+ DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
+
+ if (fake_sendfile(fsp, startpos, nread, outbuf + 4, out_buffsize - 4) == -1) {
+ DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server("send_file_readbraw fake_sendfile failed");
+ }
+ return;
}
DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
@@ -1766,7 +1813,8 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
}
- normal_read:
+ normal_readbraw:
+
#endif
if (nread > 0) {
@@ -1789,7 +1837,7 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
Reply to a readbraw (core+ protocol).
****************************************************************************/
-int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
+int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int out_buffsize)
{
extern struct current_user current_user;
ssize_t maxcount,mincount;
@@ -1878,7 +1926,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
/* ensure we don't overrun the packet size */
maxcount = MIN(65535,maxcount);
- if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
SMB_OFF_T size = fsp->size;
SMB_OFF_T sizeneeded = startpos + maxcount;
@@ -1904,7 +1952,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
(int)maxcount, (int)mincount, (int)nread ) );
- send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf);
+ send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf, out_buffsize);
DEBUG(5,("readbraw finished\n"));
END_PROFILE(SMBreadbraw);
@@ -2038,7 +2086,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
data = smb_buf(outbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBread);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2068,9 +2116,10 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
Reply to a read and X - possibly using sendfile.
****************************************************************************/
-int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length,
+int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf,
files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
{
+ int outsize = 0;
ssize_t nread = -1;
char *data = smb_buf(outbuf);
@@ -2107,6 +2156,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
SSVAL(outbuf,smb_vwv5,smb_maxcnt);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+ SSVAL(outbuf,smb_vwv7,((smb_maxcnt >> 16) & 1));
SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
SCVAL(outbuf,smb_vwv0,0xFF);
set_message(outbuf,12,smb_maxcnt,False);
@@ -2114,14 +2164,33 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
header.length = data - outbuf;
header.free = NULL;
- if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) {
+ if ((nread = SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt)) == -1) {
+ /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
+ if (errno == ENOSYS) {
+ goto normal_read;
+ }
+
/*
- * Special hack for broken Linux with no 64 bit clean sendfile. If we
- * return ENOSYS then pretend we just got a normal read.
+ * Special hack for broken Linux with no working sendfile. If we
+ * return EINTR we sent the header but not the rest of the data.
+ * Fake this up by doing read/write calls.
*/
- if (errno == ENOSYS) {
+
+ if (errno == EINTR) {
+ /* Ensure we don't do this again. */
set_use_sendfile(SNUM(conn), False);
- goto normal_read;
+ DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
+
+ if ((nread = fake_sendfile(fsp, startpos, smb_maxcnt, data,
+ len_outbuf - (data-outbuf))) == -1) {
+ DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ exit_server("send_file_readX: fake_sendfile failed");
+ }
+ DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
+ fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+ /* Returning -1 here means successful sendfile. */
+ return -1;
}
DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
@@ -2131,6 +2200,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+ /* Returning -1 here means successful sendfile. */
return -1;
}
@@ -2145,15 +2215,18 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
+ outsize = set_message(outbuf,12,nread,False);
SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
SSVAL(outbuf,smb_vwv5,nread);
SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+ SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
SSVAL(smb_buf(outbuf),-2,nread);
DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
fsp->fnum, (int)smb_maxcnt, (int)nread ) );
- return nread;
+ /* Returning the number of bytes we want to send back - including header. */
+ return outsize;
}
/****************************************************************************
@@ -2183,6 +2256,18 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
set_message(outbuf,12,0,True);
+ if (global_client_caps & CAP_LARGE_READX) {
+ if (SVAL(inbuf,smb_vwv7) == 1) {
+ smb_maxcnt |= (1<<16);
+ }
+ if (smb_maxcnt > BUFFER_SIZE) {
+ DEBUG(0,("reply_read_and_X - read too large (%u) for reply buffer %u\n",
+ (unsigned int)smb_maxcnt, (unsigned int)BUFFER_SIZE));
+ END_PROFILE(SMBreadX);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ }
+
if(CVAL(inbuf,smb_wct) == 12) {
#ifdef LARGE_SMB_OFF_T
/*
@@ -2207,12 +2292,12 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
}
- if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBreadX);
return ERROR_DOS(ERRDOS,ERRlock);
}
- nread = send_file_readX(conn, inbuf, outbuf, length, fsp, startpos, smb_maxcnt);
+ nread = send_file_readX(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt);
if (nread != -1)
nread = chain_reply(inbuf,outbuf,length,bufsize);
@@ -2263,7 +2348,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
SCVAL(inbuf,smb_com,SMBwritec);
SCVAL(outbuf,smb_com,SMBwritec);
- if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwritebraw);
return(ERROR_DOS(ERRDOS,ERRlock));
}
@@ -2378,8 +2463,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos,
- WRITE_LOCK,False)) {
+ if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteunlock);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2447,7 +2531,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwrite);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2558,7 +2642,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
#endif /* LARGE_SMB_OFF_T */
}
- if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteX);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -2829,7 +2913,7 @@ int reply_writeclose(connection_struct *conn,
mtime = make_unix_date3(inbuf+smb_vwv4);
data = smb_buf(inbuf) + 1;
- if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+ if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
END_PROFILE(SMBwriteclose);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -3223,7 +3307,7 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
}
if (check_name(directory, conn))
- ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
+ ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
if (ret == -1) {
if(errno == ENOENT) {
@@ -4518,7 +4602,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
/* we don't support these - and CANCEL_LOCK makes w2k
and XP reboot so I don't really want to be
compatible! (tridge) */
- return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
}
if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
@@ -4733,7 +4817,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
tcount = maxcount;
total_read = 0;
- if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
END_PROFILE(SMBreadBmpx);
return ERROR_DOS(ERRDOS,ERRlock);
}
@@ -4859,7 +4943,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
not an SMBwritebmpx - set this up now so we don't forget */
SCVAL(outbuf,smb_com,SMBwritec);
- if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) {
+ if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK)) {
END_PROFILE(SMBwriteBmpx);
return(ERROR_DOS(ERRDOS,ERRlock));
}
diff --git a/source/smbd/server.c b/source/smbd/server.c
index bf1da1a0c87..724a49321a2 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -186,6 +186,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
int fd_listenset[FD_SETSIZE];
fd_set listen_set;
int s;
+ int maxfd = 0;
int i;
char *ports;
@@ -241,7 +242,9 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
for (ptr=ports; next_token(&ptr, tok, NULL, sizeof(tok)); ) {
unsigned port = atoi(tok);
- if (port == 0) continue;
+ if (port == 0) {
+ continue;
+ }
s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
if(s == -1)
return False;
@@ -259,6 +262,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
return False;
}
FD_SET(s,&listen_set);
+ maxfd = MAX( maxfd, s);
num_sockets++;
if (num_sockets >= FD_SETSIZE) {
@@ -301,6 +305,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
fd_listenset[num_sockets] = s;
FD_SET(s,&listen_set);
+ maxfd = MAX( maxfd, s);
num_sockets++;
@@ -335,7 +340,7 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
memcpy((char *)&lfds, (char *)&listen_set,
sizeof(listen_set));
- num = sys_select(FD_SETSIZE,&lfds,NULL,NULL,NULL);
+ num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL);
if (num == -1 && errno == EINTR) {
if (got_sig_term) {
@@ -482,9 +487,10 @@ BOOL reload_services(BOOL test)
return(True);
lp_killunused(conn_snum_used);
-
+
ret = lp_load(dyn_CONFIGFILE, False, False, True);
+ remove_stale_printers();
load_printers();
/* perhaps the config filename is now set */
@@ -780,6 +786,9 @@ void build_options(BOOL screen);
init_structs();
+ if (!init_guest_info())
+ return -1;
+
#ifdef WITH_PROFILE
if (!profile_setup(False)) {
DEBUG(0,("ERROR: failed to setup profiling\n"));
@@ -855,7 +864,7 @@ void build_options(BOOL screen);
smbd is launched via inetd and we fork a copy of
ourselves here */
- if ( is_daemon )
+ if ( is_daemon && !interactive )
start_background_queue();
if (!open_sockets_smbd(is_daemon, interactive, ports))
diff --git a/source/smbd/service.c b/source/smbd/service.c
index 4d111e0ea35..3dcd803a7ce 100644
--- a/source/smbd/service.c
+++ b/source/smbd/service.c
@@ -152,10 +152,9 @@ int find_service(fstring service)
int iPrinterService;
if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
- char *pszTemp;
+ const char *pszTemp = lp_printcapname();
DEBUG(3,("checking whether %s is a valid printer name...\n", service));
- pszTemp = lp_printcapname();
if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp)) {
DEBUG(3,("%s is a valid printer name\n", service));
DEBUG(3,("adding %s as a printer service\n", service));
@@ -877,12 +876,21 @@ void remove_stale_printers( void )
iNumServices = lp_numservices();
printersServiceNum = lp_servicenumber( PRINTERS_NAME);
for( snum = 0; snum < iNumServices; snum++) {
+
/* Never remove PRINTERS_NAME */
+
if ( snum == printersServiceNum)
continue;
pname = lp_printername( snum);
- /* Is snum a print service and still in the printing subsystem? */
- if ( lp_print_ok( snum) && !pcap_printername_ok( pname, NULL)) {
+
+ /* Is snum an autoloaded print service and still
+ in the printing subsystem? */
+
+ if ( lp_snum_ok(snum)
+ && lp_print_ok(snum)
+ && lp_autoloaded(snum)
+ && !pcap_printername_ok( pname, NULL))
+ {
DEBUG( 3, ( "Removing printer: %s\n", pname));
lp_killservice( snum);
}
diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c
index 0122b662ebf..cff7d7371c6 100644
--- a/source/smbd/sesssetup.c
+++ b/source/smbd/sesssetup.c
@@ -633,7 +633,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
static BOOL done_sesssetup = False;
extern BOOL global_encrypted_passwords_negotiated;
extern BOOL global_spnego_negotiated;
- extern int Protocol;
+ extern enum protocol_types Protocol;
extern int max_send;
auth_usersupplied_info *user_info = NULL;
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 720ede9c767..7269ab91579 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -23,7 +23,7 @@
#include "includes.h"
-extern int Protocol;
+extern enum protocol_types Protocol;
extern int smb_read_error;
extern fstring local_machine;
extern int global_oplock_break;
@@ -584,7 +584,8 @@ static int send_trans2_replies(char *outbuf,
****************************************************************************/
static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
char *params = *pparams;
int16 open_mode;
@@ -962,8 +963,13 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
adate &= ~1;
}
- if(mode & aDIR)
+ if(mode & aDIR) {
+ /* This is necessary, as otherwise the
+ * desktop.ini file in this folder is
+ * ignored */
+ mode |= (lp_profile_acls(SNUM(conn)) ? aRONLY : 0);
file_size = 0;
+ }
DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
@@ -1317,21 +1323,22 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
****************************************************************************/
static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
/* We must be careful here that we don't return more than the
allowed number of data bytes. If this means returning fewer than
maxentries then so be it. We assume that the redirector has
enough room for the fixed number of parameter bytes it has
requested. */
- uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *params = *pparams;
char *pdata = *ppdata;
int dirtype = SVAL(params,0);
int maxentries = SVAL(params,2);
- BOOL close_after_first = BITSETW(params+4,0);
- BOOL close_if_end = BITSETW(params+4,1);
- BOOL requires_resume_key = BITSETW(params+4,2);
+ uint16 findfirst_flags = SVAL(params,4);
+ BOOL close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
+ BOOL close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
+ BOOL requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
int info_level = SVAL(params,6);
pstring directory;
pstring mask;
@@ -1541,24 +1548,25 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
****************************************************************************/
static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
/* We must be careful here that we don't return more than the
allowed number of data bytes. If this means returning fewer than
maxentries then so be it. We assume that the redirector has
enough room for the fixed number of parameter bytes it has
requested. */
- int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *params = *pparams;
char *pdata = *ppdata;
int dptr_num = SVAL(params,0);
int maxentries = SVAL(params,2);
uint16 info_level = SVAL(params,4);
uint32 resume_key = IVAL(params,6);
- BOOL close_after_request = BITSETW(params+10,0);
- BOOL close_if_end = BITSETW(params+10,1);
- BOOL requires_resume_key = BITSETW(params+10,2);
- BOOL continue_bit = BITSETW(params+10,3);
+ uint16 findnext_flags = SVAL(params,10);
+ BOOL close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
+ BOOL close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
+ BOOL requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
+ BOOL continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
pstring resume_name;
pstring mask;
pstring directory;
@@ -1807,11 +1815,10 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
Reply to a TRANS2_QFSINFO (query filesystem info).
****************************************************************************/
-static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf,
- int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
- int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *pdata = *ppdata;
char *params = *pparams;
uint16 info_level = SVAL(params,0);
@@ -2084,7 +2091,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
data_len = 12;
SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
- SBIG_UINT(pdata,4,((SMB_BIG_UINT)0)); /* No capabilities for now... */
+ SBIG_UINT(pdata,4,((SMB_BIG_UINT)CIFS_UNIX_POSIX_ACLS_CAP)); /* We have POSIX ACLs. */
break;
case SMB_MAC_QUERY_FS_INFO:
@@ -2115,9 +2122,9 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
Reply to a TRANS2_SETFSINFO (set filesystem info).
****************************************************************************/
-static int call_trans2setfsinfo(connection_struct *conn,
- char *inbuf, char *outbuf, int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
char *pdata = *ppdata;
char *params = *pparams;
@@ -2225,8 +2232,8 @@ static int call_trans2setfsinfo(connection_struct *conn,
#endif /* HAVE_SYS_QUOTAS */
/****************************************************************************
- * Utility function to set bad path error.
- ****************************************************************************/
+ Utility function to set bad path error.
+****************************************************************************/
int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint32 def_code)
{
@@ -2244,16 +2251,129 @@ int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint
}
/****************************************************************************
+ Utility function to count the number of entries in a POSIX acl.
+****************************************************************************/
+
+static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
+{
+ unsigned int ace_count = 0;
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+
+ while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+ /* get_next... */
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ entry_id = SMB_ACL_NEXT_ENTRY;
+ }
+ ace_count++;
+ }
+ return ace_count;
+}
+
+/****************************************************************************
+ Utility function to marshall a POSIX acl into wire format.
+****************************************************************************/
+
+static BOOL marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
+{
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+
+ while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+ unsigned char perms = 0;
+ unsigned int own_grp;
+
+ /* get_next... */
+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
+ entry_id = SMB_ACL_NEXT_ENTRY;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+ DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
+ return False;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
+ return False;
+ }
+
+ perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
+ perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
+ perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
+
+ SCVAL(pdata,1,perms);
+
+ switch (tagtype) {
+ case SMB_ACL_USER_OBJ:
+ SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
+ own_grp = (unsigned int)pst->st_uid;
+ SIVAL(pdata,2,own_grp);
+ SIVAL(pdata,6,0);
+ break;
+ case SMB_ACL_USER:
+ {
+ uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ if (!puid) {
+ DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
+ }
+ own_grp = (unsigned int)*puid;
+ SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
+ SCVAL(pdata,0,SMB_POSIX_ACL_USER);
+ SIVAL(pdata,2,own_grp);
+ SIVAL(pdata,6,0);
+ break;
+ }
+ case SMB_ACL_GROUP_OBJ:
+ SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
+ own_grp = (unsigned int)pst->st_gid;
+ SIVAL(pdata,2,own_grp);
+ SIVAL(pdata,6,0);
+ break;
+ case SMB_ACL_GROUP:
+ {
+ gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ if (!pgid) {
+ DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
+ }
+ own_grp = (unsigned int)*pgid;
+ SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
+ SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
+ SIVAL(pdata,2,own_grp);
+ SIVAL(pdata,6,0);
+ break;
+ }
+ case SMB_ACL_MASK:
+ SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
+ SIVAL(pdata,2,0xFFFFFFFF);
+ SIVAL(pdata,6,0xFFFFFFFF);
+ break;
+ case SMB_ACL_OTHER:
+ SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
+ SIVAL(pdata,2,0xFFFFFFFF);
+ SIVAL(pdata,6,0xFFFFFFFF);
+ break;
+ default:
+ DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
+ return False;
+ }
+ pdata += SMB_POSIX_ACL_ENTRY_SIZE;
+ }
+
+ return True;
+}
+
+/****************************************************************************
Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
file name or file id).
****************************************************************************/
-static int call_trans2qfilepathinfo(connection_struct *conn,
- char *inbuf, char *outbuf, int length,
- int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
- int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *params = *pparams;
char *pdata = *ppdata;
uint16 tran_call = SVAL(inbuf, smb_setup0);
@@ -2392,8 +2512,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
fullpathname = fname;
file_size = get_file_size(sbuf);
allocation_size = get_allocation_size(fsp,&sbuf);
- if (mode & aDIR)
+ if (mode & aDIR) {
+ /* This is necessary, as otherwise the desktop.ini file in
+ * this folder is ignored */
+ mode |= (lp_profile_acls(SNUM(conn)) ? aRONLY : 0);
file_size = 0;
+ }
params = SMB_REALLOC(*pparams,2);
if (params == NULL)
@@ -2416,6 +2540,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ if (fsp && fsp->pending_modtime) {
+ /* the pending modtime overrides the current modtime */
+ sbuf.st_mtime = fsp->pending_modtime;
+ }
+
if (lp_dos_filetime_resolution(SNUM(conn))) {
c_time &= ~1;
sbuf.st_atime &= ~1;
@@ -2800,6 +2929,83 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
break;
}
+ case SMB_QUERY_POSIX_ACL:
+ {
+ SMB_ACL_T file_acl = NULL;
+ SMB_ACL_T def_acl = NULL;
+ uint16 num_file_acls = 0;
+ uint16 num_def_acls = 0;
+
+ if (fsp && !fsp->is_directory && (fsp->fd != -1)) {
+ file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
+ } else {
+ file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
+ }
+
+ if (file_acl == NULL && no_acl_syscall_error(errno)) {
+ DEBUG(5,("call_trans2qfilepathinfo: ACLs not implemented on filesystem containing %s\n",
+ fname ));
+ return ERROR_NT(NT_STATUS_NOT_IMPLEMENTED);
+ }
+
+ if (S_ISDIR(sbuf.st_mode)) {
+ if (fsp && fsp->is_directory) {
+ def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
+ } else {
+ def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT);
+ }
+ def_acl = free_empty_sys_acl(conn, def_acl);
+ }
+
+ num_file_acls = count_acl_entries(conn, file_acl);
+ num_def_acls = count_acl_entries(conn, def_acl);
+
+ if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
+ DEBUG(5,("call_trans2qfilepathinfo: data_size too small (%u) need %u\n",
+ data_size,
+ (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
+ SMB_POSIX_ACL_HEADER_SIZE) ));
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL);
+ }
+
+ SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
+ SSVAL(pdata,2,num_file_acls);
+ SSVAL(pdata,4,num_def_acls);
+ if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, &sbuf, file_acl)) {
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+ }
+ if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), &sbuf, def_acl)) {
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+ }
+
+ if (file_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ }
+ if (def_acl) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ }
+ data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
+ break;
+ }
+
default:
return ERROR_DOS(ERRDOS,ERRunknownlevel);
}
@@ -2981,9 +3187,9 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
Reply to a TRANS2_SETFILEINFO (set file info by fileid).
****************************************************************************/
-static int call_trans2setfilepathinfo(connection_struct *conn,
- char *inbuf, char *outbuf, int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
char *params = *pparams;
char *pdata = *ppdata;
@@ -3103,7 +3309,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
SSVAL(params,0,0);
- if (fsp) {
+ if (fsp && fsp->pending_modtime) {
/* the pending modtime overrides the current modtime */
sbuf.st_mtime = fsp->pending_modtime;
}
@@ -3607,6 +3813,57 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
return(-1);
}
+
+ case SMB_SET_POSIX_ACL:
+ {
+ uint16 posix_acl_version;
+ uint16 num_file_acls;
+ uint16 num_def_acls;
+ BOOL valid_file_acls = True;
+ BOOL valid_def_acls = True;
+
+ if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+ }
+ posix_acl_version = SVAL(pdata,0);
+ num_file_acls = SVAL(pdata,2);
+ num_def_acls = SVAL(pdata,4);
+
+ if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
+ valid_file_acls = False;
+ num_file_acls = 0;
+ }
+
+ if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
+ valid_def_acls = False;
+ num_def_acls = 0;
+ }
+
+ if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+ }
+
+ if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
+ (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+ }
+
+ if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls,
+ pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ if (valid_def_acls && !set_unix_posix_default_acl(conn, fname, &sbuf, num_def_acls,
+ pdata + SMB_POSIX_ACL_HEADER_SIZE +
+ (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
+ }
+
default:
return ERROR_DOS(ERRDOS,ERRunknownlevel);
}
@@ -3652,10 +3909,12 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
if(fsp != NULL) {
/*
* This was a setfileinfo on an open file.
- * NT does this a lot. It's actually pointless
- * setting the time here, as it will be overwritten
- * on the next write, so we save the request
- * away and will set it on file close. JRA.
+ * NT does this a lot. We also need to
+ * set the time here, as it can be read by
+ * FindFirst/FindNext and with the patch for bug #2045
+ * in smbd/fileio.c it ensures that this timestamp is
+ * kept sticky even after a write. We save the request
+ * away and will set it on file close and after a write. JRA.
*/
if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
@@ -3663,12 +3922,11 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
fsp->pending_modtime = tvs.modtime;
}
- } else {
-
DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
- if(file_utime(conn, fname, &tvs)!=0)
+ if(file_utime(conn, fname, &tvs)!=0) {
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
}
}
@@ -3677,7 +3935,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, dosmode ));
- if(file_set_dosmode(conn, fname, dosmode, NULL)) {
+ if(file_set_dosmode(conn, fname, dosmode, &sbuf, False)) {
DEBUG(2,("file_set_dosmode of %s failed (%s)\n", fname, strerror(errno)));
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -3733,9 +3991,9 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
Reply to a TRANS2_MKDIR (make directory with extended attributes).
****************************************************************************/
-static int call_trans2mkdir(connection_struct *conn,
- char *inbuf, char *outbuf, int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
char *params = *pparams;
pstring directory;
@@ -3762,7 +4020,7 @@ static int call_trans2mkdir(connection_struct *conn,
return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
}
if (check_name(directory,conn))
- ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
+ ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
if(ret < 0) {
DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
@@ -3787,9 +4045,9 @@ static int call_trans2mkdir(connection_struct *conn,
We don't actually do this - we just send a null response.
****************************************************************************/
-static int call_trans2findnotifyfirst(connection_struct *conn,
- char *inbuf, char *outbuf, int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
static uint16 fnf_handle = 257;
char *params = *pparams;
@@ -3834,9 +4092,9 @@ static int call_trans2findnotifyfirst(connection_struct *conn,
changes). Currently this does nothing.
****************************************************************************/
-static int call_trans2findnotifynext(connection_struct *conn,
- char *inbuf, char *outbuf, int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2findnotifynext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
char *params = *pparams;
@@ -3860,9 +4118,9 @@ static int call_trans2findnotifynext(connection_struct *conn,
Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
****************************************************************************/
-static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
- char* outbuf, int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
char *params = *pparams;
pstring pathname;
@@ -3896,9 +4154,9 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
Reply to a TRANS2_IOCTL - used for OS/2 printing.
****************************************************************************/
-static int call_trans2ioctl(connection_struct *conn, char* inbuf,
- char* outbuf, int length, int bufsize,
- char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2ioctl(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
+ char **pparams, int total_params, char **ppdata, int total_data,
+ unsigned int max_data_bytes)
{
char *pdata = *ppdata;
files_struct *fsp = file_fsp(inbuf,smb_vwv15);
@@ -4002,9 +4260,9 @@ int reply_trans2(connection_struct *conn,
int outsize = 0;
unsigned int total_params = SVAL(inbuf, smb_tpscnt);
unsigned int total_data =SVAL(inbuf, smb_tdscnt);
+ unsigned int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
#if 0
unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
- unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
BOOL close_tid = BITSETW(inbuf+smb_flags,0);
BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
@@ -4159,7 +4417,7 @@ int reply_trans2(connection_struct *conn,
goto bad_param;
if (num_params) {
- if (param_disp + num_params >= total_params)
+ if (param_disp + num_params > total_params)
goto bad_param;
if ((param_disp + num_params < param_disp) ||
(param_disp + num_params < num_params))
@@ -4175,7 +4433,7 @@ int reply_trans2(connection_struct *conn,
memcpy( &params[param_disp], smb_base(inbuf) + param_off, num_params);
}
if (num_data) {
- if (data_disp + num_data >= total_data)
+ if (data_disp + num_data > total_data)
goto bad_param;
if ((data_disp + num_data < data_disp) ||
(data_disp + num_data < num_data))
@@ -4202,28 +4460,28 @@ int reply_trans2(connection_struct *conn,
case TRANSACT2_OPEN:
START_PROFILE_NESTED(Trans2_open);
outsize = call_trans2open(conn, inbuf, outbuf, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_open);
break;
case TRANSACT2_FINDFIRST:
START_PROFILE_NESTED(Trans2_findfirst);
outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_findfirst);
break;
case TRANSACT2_FINDNEXT:
START_PROFILE_NESTED(Trans2_findnext);
outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_findnext);
break;
case TRANSACT2_QFSINFO:
START_PROFILE_NESTED(Trans2_qfsinfo);
outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_qfsinfo);
break;
@@ -4231,7 +4489,7 @@ int reply_trans2(connection_struct *conn,
case TRANSACT2_SETFSINFO:
START_PROFILE_NESTED(Trans2_setfsinfo);
outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_setfsinfo);
break;
#endif
@@ -4239,47 +4497,47 @@ int reply_trans2(connection_struct *conn,
case TRANSACT2_QFILEINFO:
START_PROFILE_NESTED(Trans2_qpathinfo);
outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_qpathinfo);
break;
case TRANSACT2_SETPATHINFO:
case TRANSACT2_SETFILEINFO:
START_PROFILE_NESTED(Trans2_setpathinfo);
outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_setpathinfo);
break;
case TRANSACT2_FINDNOTIFYFIRST:
START_PROFILE_NESTED(Trans2_findnotifyfirst);
outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_findnotifyfirst);
break;
case TRANSACT2_FINDNOTIFYNEXT:
START_PROFILE_NESTED(Trans2_findnotifynext);
outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_findnotifynext);
break;
case TRANSACT2_MKDIR:
START_PROFILE_NESTED(Trans2_mkdir);
outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_mkdir);
break;
case TRANSACT2_GET_DFS_REFERRAL:
START_PROFILE_NESTED(Trans2_get_dfs_referral);
outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_get_dfs_referral);
break;
case TRANSACT2_IOCTL:
START_PROFILE_NESTED(Trans2_ioctl);
outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize,
- &params, total_params, &data, total_data);
+ &params, total_params, &data, total_data, max_data_bytes);
END_PROFILE_NESTED(Trans2_ioctl);
break;
default:
diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c
index 5393dfc7556..abc17a37a23 100644
--- a/source/smbd/vfs-wrap.c
+++ b/source/smbd/vfs-wrap.c
@@ -93,21 +93,44 @@ DIR *vfswrap_opendir(vfs_handle_struct *handle, connection_struct *conn, const c
DIR *result;
START_PROFILE(syscall_opendir);
- result = opendir(fname);
+ result = sys_opendir(fname);
END_PROFILE(syscall_opendir);
return result;
}
-struct dirent *vfswrap_readdir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp)
+SMB_STRUCT_DIRENT *vfswrap_readdir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp)
{
- struct dirent *result;
+ SMB_STRUCT_DIRENT *result;
START_PROFILE(syscall_readdir);
- result = readdir(dirp);
+ result = sys_readdir(dirp);
END_PROFILE(syscall_readdir);
return result;
}
+void vfswrap_seekdir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp, long offset)
+{
+ START_PROFILE(syscall_seekdir);
+ sys_seekdir(dirp, offset);
+ END_PROFILE(syscall_seekdir);
+}
+
+long vfswrap_telldir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp)
+{
+ long result;
+ START_PROFILE(syscall_telldir);
+ result = sys_telldir(dirp);
+ END_PROFILE(syscall_telldir);
+ return result;
+}
+
+void vfswrap_rewinddir(vfs_handle_struct *handle, connection_struct *conn, DIR *dirp)
+{
+ START_PROFILE(syscall_rewinddir);
+ sys_rewinddir(dirp);
+ END_PROFILE(syscall_rewinddir);
+}
+
int vfswrap_mkdir(vfs_handle_struct *handle, connection_struct *conn, const char *path, mode_t mode)
{
int result;
@@ -152,7 +175,7 @@ int vfswrap_closedir(vfs_handle_struct *handle, connection_struct *conn, DIR *di
int result;
START_PROFILE(syscall_closedir);
- result = closedir(dirp);
+ result = sys_closedir(dirp);
END_PROFILE(syscall_closedir);
return result;
}
diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c
index 68a6dca31dd..0102739fe39 100644
--- a/source/smbd/vfs.c
+++ b/source/smbd/vfs.c
@@ -62,6 +62,9 @@ static struct vfs_ops default_vfs = {
vfswrap_opendir,
vfswrap_readdir,
+ vfswrap_seekdir,
+ vfswrap_telldir,
+ vfswrap_rewinddir,
vfswrap_mkdir,
vfswrap_rmdir,
vfswrap_closedir,
@@ -611,13 +614,13 @@ SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
char *vfs_readdirname(connection_struct *conn, void *p)
{
- struct dirent *ptr= NULL;
+ SMB_STRUCT_DIRENT *ptr= NULL;
char *dname;
if (!p)
return(NULL);
- ptr = (struct dirent *)SMB_VFS_READDIR(conn,p);
+ ptr = SMB_VFS_READDIR(conn,p);
if (!ptr)
return(NULL);
@@ -894,7 +897,8 @@ BOOL reduce_name(connection_struct *conn, const pstring fname)
}
default:
DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
- errno = saved_errno;
+ /* Don't restore the saved errno. We need to return the error that
+ realpath caused here as it was not one of the cases we handle. JRA. */
return False;
}
}