summaryrefslogtreecommitdiff
path: root/source/smbd
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2005-02-25 14:08:30 +0000
committerGerald Carter <jerry@samba.org>2005-02-25 14:08:30 +0000
commit70cd25be8b07743816b9376f9d219453f0f906fc (patch)
tree073f3d33dac8c96b0d4c7b809b3dc86b91023214 /source/smbd
parent1d58e0d7811acc335f09128ae757f5f76a51644d (diff)
downloadsamba-70cd25be8b07743816b9376f9d219453f0f906fc.tar.gz
r5555: current with 3.0 tree as of r5548; getting ready for 3.0.12pre1
Diffstat (limited to 'source/smbd')
-rw-r--r--source/smbd/dfree.c10
-rw-r--r--source/smbd/dir.c652
-rw-r--r--source/smbd/filename.c12
-rw-r--r--source/smbd/notify_hash.c18
-rw-r--r--source/smbd/nttrans.c53
-rw-r--r--source/smbd/posix_acls.c157
-rw-r--r--source/smbd/reply.c158
-rw-r--r--source/smbd/service.c27
-rw-r--r--source/smbd/sesssetup.c8
-rw-r--r--source/smbd/trans2.c171
10 files changed, 774 insertions, 492 deletions
diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c
index f93cdf3791e..c556c8c8ab2 100644
--- a/source/smbd/dfree.c
+++ b/source/smbd/dfree.c
@@ -36,11 +36,11 @@ static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,
errors */
}
- while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
- *dfree /= 2;
- *dsize /= 2;
- *bsize *= 2;
- if(small_query) {
+ if(small_query) {
+ while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
+ *dfree /= 2;
+ *dsize /= 2;
+ *bsize *= 2;
/*
* Force max to fit in 16 bit fields.
*/
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index f721bf3ba8a..7dde18f4306 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -24,22 +24,40 @@
This module implements directory related functions for Samba.
*/
-typedef struct _dptr_struct {
- struct _dptr_struct *next, *prev;
+/* Make directory handle internals available. */
+
+#define NAME_CACHE_SIZE 100
+
+struct name_cache_entry {
+ char *name;
+ long offset;
+};
+
+struct smb_Dir {
+ connection_struct *conn;
+ DIR *dir;
+ long offset;
+ char *dir_path;
+ struct name_cache_entry *name_cache;
+ unsigned int name_cache_index;
+};
+
+struct dptr_struct {
+ struct dptr_struct *next, *prev;
int dnum;
uint16 spid;
- connection_struct *conn;
- void *ptr;
+ struct connection_struct *conn;
+ struct smb_Dir *dir_hnd;
BOOL expect_close;
- char *wcard; /* Field only used for trans2_ searches */
- uint16 attr; /* Field only used for trans2_ searches */
+ char *wcard;
+ uint16 attr;
char *path;
-} dptr_struct;
+ BOOL has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
+};
static struct bitmap *dptr_bmap;
-static dptr_struct *dirptrs;
-
-static int dptrs_open = 0;
+static struct dptr_struct *dirptrs;
+static int dirhandles_open = 0;
#define INVALID_DPTR_KEY (-3)
@@ -66,13 +84,12 @@ void init_dptrs(void)
Idle a dptr - the directory is closed but the control info is kept.
****************************************************************************/
-static void dptr_idle(dptr_struct *dptr)
+static void dptr_idle(struct dptr_struct *dptr)
{
- if (dptr->ptr) {
+ if (dptr->dir_hnd) {
DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
- dptrs_open--;
- CloseDir(dptr->ptr);
- dptr->ptr = NULL;
+ CloseDir(dptr->dir_hnd);
+ dptr->dir_hnd = NULL;
}
}
@@ -82,7 +99,7 @@ static void dptr_idle(dptr_struct *dptr)
static void dptr_idleoldest(void)
{
- dptr_struct *dptr;
+ struct dptr_struct *dptr;
/*
* Go to the end of the list.
@@ -100,7 +117,7 @@ static void dptr_idleoldest(void)
*/
for(; dptr; dptr = dptr->prev) {
- if (dptr->ptr) {
+ if (dptr->dir_hnd) {
dptr_idle(dptr);
return;
}
@@ -108,21 +125,24 @@ static void dptr_idleoldest(void)
}
/****************************************************************************
- Get the dptr_struct for a dir index.
+ Get the struct dptr_struct for a dir index.
****************************************************************************/
-static dptr_struct *dptr_get(int key, BOOL forclose)
+static struct dptr_struct *dptr_get(int key, BOOL forclose)
{
- dptr_struct *dptr;
+ struct dptr_struct *dptr;
for(dptr = dirptrs; dptr; dptr = dptr->next) {
if(dptr->dnum == key) {
- if (!forclose && !dptr->ptr) {
- if (dptrs_open >= MAX_OPEN_DIRECTORIES)
+ if (!forclose && !dptr->dir_hnd) {
+ if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
dptr_idleoldest();
- DEBUG(4,("Reopening dptr key %d\n",key));
- if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
- dptrs_open++;
+ DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
+ if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path))) {
+ DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
+ strerror(errno)));
+ return False;
+ }
}
DLIST_PROMOTE(dirptrs,dptr);
return dptr;
@@ -132,94 +152,70 @@ static dptr_struct *dptr_get(int key, BOOL forclose)
}
/****************************************************************************
- Get the dptr ptr for a dir index.
-****************************************************************************/
-
-static void *dptr_ptr(int key)
-{
- dptr_struct *dptr = dptr_get(key, False);
-
- if (dptr)
- return(dptr->ptr);
- return(NULL);
-}
-
-/****************************************************************************
Get the dir path for a dir index.
****************************************************************************/
char *dptr_path(int key)
{
- dptr_struct *dptr = dptr_get(key, False);
-
+ struct dptr_struct *dptr = dptr_get(key, False);
if (dptr)
return(dptr->path);
return(NULL);
}
/****************************************************************************
- Get the dir wcard for a dir index (lanman2 specific).
+ Get the dir wcard for a dir index.
****************************************************************************/
char *dptr_wcard(int key)
{
- dptr_struct *dptr = dptr_get(key, False);
-
+ struct dptr_struct *dptr = dptr_get(key, False);
if (dptr)
return(dptr->wcard);
return(NULL);
}
/****************************************************************************
- Set the dir wcard for a dir index (lanman2 specific).
- Returns 0 on ok, 1 on fail.
+ Get the dir attrib for a dir index.
****************************************************************************/
-BOOL dptr_set_wcard(int key, char *wcard)
+uint16 dptr_attr(int key)
{
- dptr_struct *dptr = dptr_get(key, False);
-
- if (dptr) {
- dptr->wcard = wcard;
- return True;
- }
- return False;
+ struct dptr_struct *dptr = dptr_get(key, False);
+ if (dptr)
+ return(dptr->attr);
+ return(0);
}
/****************************************************************************
- Set the dir attrib for a dir index (lanman2 specific).
+ Set the dir wcard for a dir index.
Returns 0 on ok, 1 on fail.
****************************************************************************/
-BOOL dptr_set_attr(int key, uint16 attr)
+BOOL dptr_set_wcard_and_attributes(int key, const char *wcard, uint16 attr)
{
- dptr_struct *dptr = dptr_get(key, False);
+ struct dptr_struct *dptr = dptr_get(key, False);
if (dptr) {
dptr->attr = attr;
+ dptr->wcard = SMB_STRDUP(wcard);
+ if (!dptr->wcard)
+ return False;
+ if (wcard[0] == '.' && wcard[1] == 0) {
+ dptr->has_wild = True;
+ } else {
+ dptr->has_wild = ms_has_wild(wcard);
+ }
return True;
}
return False;
}
/****************************************************************************
- Get the dir attrib for a dir index (lanman2 specific)
-****************************************************************************/
-
-uint16 dptr_attr(int key)
-{
- dptr_struct *dptr = dptr_get(key, False);
-
- if (dptr)
- return(dptr->attr);
- return(0);
-}
-
-/****************************************************************************
Close a dptr (internal func).
****************************************************************************/
-static void dptr_close_internal(dptr_struct *dptr)
+static void dptr_close_internal(struct dptr_struct *dptr)
{
DEBUG(4,("closing dptr key %d\n",dptr->dnum));
@@ -237,9 +233,8 @@ static void dptr_close_internal(dptr_struct *dptr)
bitmap_clear(dptr_bmap, dptr->dnum - 1);
- if (dptr->ptr) {
- CloseDir(dptr->ptr);
- dptrs_open--;
+ if (dptr->dir_hnd) {
+ CloseDir(dptr->dir_hnd);
}
/* Lanman 2 specific code */
@@ -254,14 +249,14 @@ static void dptr_close_internal(dptr_struct *dptr)
void dptr_close(int *key)
{
- dptr_struct *dptr;
+ struct dptr_struct *dptr;
if(*key == INVALID_DPTR_KEY)
return;
/* OS/2 seems to use -1 to indicate "close all directories" */
if (*key == -1) {
- dptr_struct *next;
+ struct dptr_struct *next;
for(dptr = dirptrs; dptr; dptr = next) {
next = dptr->next;
dptr_close_internal(dptr);
@@ -288,7 +283,7 @@ void dptr_close(int *key)
void dptr_closecnum(connection_struct *conn)
{
- dptr_struct *dptr, *next;
+ struct dptr_struct *dptr, *next;
for(dptr = dirptrs; dptr; dptr = next) {
next = dptr->next;
if (dptr->conn == conn)
@@ -302,9 +297,9 @@ void dptr_closecnum(connection_struct *conn)
void dptr_idlecnum(connection_struct *conn)
{
- dptr_struct *dptr;
+ struct dptr_struct *dptr;
for(dptr = dirptrs; dptr; dptr = dptr->next) {
- if (dptr->conn == conn && dptr->ptr)
+ if (dptr->conn == conn && dptr->dir_hnd)
dptr_idle(dptr);
}
}
@@ -315,7 +310,7 @@ void dptr_idlecnum(connection_struct *conn)
void dptr_closepath(char *path,uint16 spid)
{
- dptr_struct *dptr, *next;
+ struct dptr_struct *dptr, *next;
for(dptr = dirptrs; dptr; dptr = next) {
next = dptr->next;
if (spid == dptr->spid && strequal(dptr->path,path))
@@ -324,35 +319,6 @@ void dptr_closepath(char *path,uint16 spid)
}
/****************************************************************************
- Start a directory listing.
-****************************************************************************/
-
-static BOOL start_dir(connection_struct *conn, pstring directory)
-{
- const char *dir2;
-
- DEBUG(5,("start_dir dir=%s\n",directory));
-
- if (!check_name(directory,conn))
- return(False);
-
- /* use a const pointer from here on */
- dir2 = directory;
-
- if (! *dir2)
- dir2 = ".";
-
- conn->dirptr = OpenDir(conn, directory, True);
- if (conn->dirptr) {
- dptrs_open++;
- string_set(&conn->dirpath,directory);
- return(True);
- }
-
- return(False);
-}
-
-/****************************************************************************
Try and close the oldest handle not marked for
expect close in the hope that the client has
finished with that one.
@@ -360,7 +326,7 @@ static BOOL start_dir(connection_struct *conn, pstring directory)
static void dptr_close_oldest(BOOL old)
{
- dptr_struct *dptr;
+ struct dptr_struct *dptr;
/*
* Go to the end of the list.
@@ -393,23 +359,39 @@ static void dptr_close_oldest(BOOL old)
from the bitmap range 0 - 255 as old SMBsearch directory handles are only
one byte long. If old_handle is false we allocate from the range
256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
- a directory handle is never zero. All the above is folklore taught to
- me at Andrew's knee.... :-) :-). JRA.
+ a directory handle is never zero.
****************************************************************************/
int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
{
- dptr_struct *dptr;
+ struct dptr_struct *dptr = NULL;
+ struct smb_Dir *dir_hnd;
+ const char *dir2;
- if (!start_dir(conn,path))
+ DEBUG(5,("dptr_create dir=%s\n", path));
+
+ if (!check_name(path,conn))
return(-2); /* Code to say use a unix error return code. */
- if (dptrs_open >= MAX_OPEN_DIRECTORIES)
+ /* use a const pointer from here on */
+ dir2 = path;
+ if (!*dir2)
+ dir2 = ".";
+
+ dir_hnd = OpenDir(conn, dir2);
+ if (!dir_hnd) {
+ return (-2);
+ }
+
+ string_set(&conn->dirpath,dir2);
+
+ if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
dptr_idleoldest();
- dptr = SMB_MALLOC_P(dptr_struct);
+ dptr = SMB_MALLOC_P(struct dptr_struct);
if(!dptr) {
DEBUG(0,("malloc fail in dptr_create.\n"));
+ CloseDir(dir_hnd);
return -1;
}
@@ -439,6 +421,7 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp
if(dptr->dnum == -1 || dptr->dnum > 254) {
DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
SAFE_FREE(dptr);
+ CloseDir(dir_hnd);
return -1;
}
}
@@ -468,6 +451,7 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp
if(dptr->dnum == -1 || dptr->dnum < 255) {
DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
SAFE_FREE(dptr);
+ CloseDir(dir_hnd);
return -1;
}
}
@@ -477,22 +461,131 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp
dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
- dptr->ptr = conn->dirptr;
- string_set(&dptr->path,path);
+ string_set(&dptr->path,dir2);
dptr->conn = conn;
+ dptr->dir_hnd = dir_hnd;
dptr->spid = spid;
dptr->expect_close = expect_close;
dptr->wcard = NULL; /* Only used in lanman2 searches */
dptr->attr = 0; /* Only used in lanman2 searches */
+ dptr->has_wild = True; /* Only used in lanman2 searches */
DLIST_ADD(dirptrs, dptr);
DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
dptr->dnum,path,expect_close));
+ conn->dirptr = dptr;
+
return(dptr->dnum);
}
+
+/****************************************************************************
+ Wrapper functions to access the lower level directory handles.
+****************************************************************************/
+
+int dptr_CloseDir(struct dptr_struct *dptr)
+{
+ return CloseDir(dptr->dir_hnd);
+}
+
+void dptr_SeekDir(struct dptr_struct *dptr, long offset)
+{
+ SeekDir(dptr->dir_hnd, offset);
+}
+
+long dptr_TellDir(struct dptr_struct *dptr)
+{
+ return TellDir(dptr->dir_hnd);
+}
+
+/****************************************************************************
+ Return the next visible file name, skipping veto'd and invisible files.
+****************************************************************************/
+
+static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
+{
+ /* Normal search for the next file. */
+ const char *name;
+ while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
+ if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
+ return name;
+ }
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ Return the next visible file name, skipping veto'd and invisible files.
+****************************************************************************/
+
+const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
+{
+ pstring pathreal;
+
+ ZERO_STRUCTP(pst);
+ if (dptr->has_wild) {
+ return dptr_normal_ReadDirName(dptr, poffset, pst);
+ }
+
+ /* We know the stored wcard contains no wildcard characters. See if we can match
+ with a stat call. If we can't, then set has_wild to true to
+ prevent us from doing this on every call. */
+
+ /* First check if it should be visible. */
+ if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
+ dptr->has_wild = True;
+ return dptr_normal_ReadDirName(dptr, poffset, pst);
+ }
+
+ if (VALID_STAT(*pst)) {
+ return dptr->wcard;
+ }
+
+ pstrcpy(pathreal,dptr->path);
+ pstrcat(pathreal,"/");
+ pstrcat(pathreal,dptr->wcard);
+
+ if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
+ return dptr->wcard;
+ } else {
+ /* If we get any other error than ENOENT or ENOTDIR
+ then the file exists we just can't stat it. */
+ if (errno != ENOENT && errno != ENOTDIR) {
+ return dptr->wcard;
+ }
+ }
+
+ dptr->has_wild = True;
+
+ /* In case sensitive mode we don't search - we know if it doesn't exist
+ with a stat we will fail. */
+
+ if (dptr->conn->case_sensitive) {
+ return NULL;
+ } else {
+ return dptr_normal_ReadDirName(dptr, poffset, pst);
+ }
+}
+
+/****************************************************************************
+ Search for a file by name, skipping veto'ed and not visible files.
+****************************************************************************/
+
+BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
+{
+ BOOL ret;
+
+ ZERO_STRUCTP(pst);
+ while ((ret = SearchDir(dptr->dir_hnd, name, poffset)) == True) {
+ if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
+ return True;
+ }
+ }
+ return False;
+}
+
/****************************************************************************
Fill the 5 byte server reserved dptr field.
****************************************************************************/
@@ -500,15 +593,15 @@ int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL exp
BOOL dptr_fill(char *buf1,unsigned int key)
{
unsigned char *buf = (unsigned char *)buf1;
- void *p = dptr_ptr(key);
+ struct dptr_struct *dptr = dptr_get(key, False);
uint32 offset;
- if (!p) {
+ if (!dptr) {
DEBUG(1,("filling null dirptr %d\n",key));
return(False);
}
- offset = TellDir(p);
+ offset = TellDir(dptr->dir_hnd);
DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
- (long)p,(int)offset));
+ (long)dptr->dir_hnd,(int)offset));
buf[0] = key;
SIVAL(buf,1,offset | DPTR_MASK);
return(True);
@@ -518,45 +611,45 @@ BOOL dptr_fill(char *buf1,unsigned int key)
Fetch the dir ptr and seek it given the 5 byte server field.
****************************************************************************/
-void *dptr_fetch(char *buf,int *num)
+struct dptr_struct *dptr_fetch(char *buf,int *num)
{
unsigned int key = *(unsigned char *)buf;
- void *p = dptr_ptr(key);
+ struct dptr_struct *dptr = dptr_get(key, False);
uint32 offset;
- if (!p) {
+ if (!dptr) {
DEBUG(3,("fetched null dirptr %d\n",key));
return(NULL);
}
*num = key;
offset = IVAL(buf,1)&~DPTR_MASK;
- SeekDir(p,offset);
+ SeekDir(dptr->dir_hnd,(long)offset);
DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
key,dptr_path(key),offset));
- return(p);
+ return(dptr);
}
/****************************************************************************
Fetch the dir ptr.
****************************************************************************/
-void *dptr_fetch_lanman2(int dptr_num)
+struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
{
- void *p = dptr_ptr(dptr_num);
+ struct dptr_struct *dptr = dptr_get(dptr_num, False);
- if (!p) {
+ if (!dptr) {
DEBUG(3,("fetched null dirptr %d\n",dptr_num));
return(NULL);
}
DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
- return(p);
+ return(dptr);
}
/****************************************************************************
Check a filetype for being valid.
****************************************************************************/
-BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
+BOOL dir_check_ftype(connection_struct *conn,int mode,int dirtype)
{
int mask;
@@ -612,10 +705,11 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname
return(False);
while (!found) {
- dname = ReadDirName(conn->dirptr);
+ long curoff = dptr_TellDir(conn->dirptr);
+ dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
- DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
- (long)conn->dirptr,TellDir(conn->dirptr)));
+ DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
+ (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
if (dname == NULL)
return(False);
@@ -643,14 +737,14 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname
pstrcpy(pathreal,path);
pstrcat(path,fname);
pstrcat(pathreal,dname);
- if (SMB_VFS_STAT(conn, pathreal, &sbuf) != 0) {
+ if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
continue;
}
*mode = dos_mode(conn,pathreal,&sbuf);
- if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) {
+ if (!dir_check_ftype(conn,*mode,dirtype)) {
DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
continue;
}
@@ -667,14 +761,6 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname
return(found);
}
-typedef struct {
- int pos;
- int numentries;
- int mallocsize;
- char *data;
- char *current;
-} Dir;
-
/*******************************************************************
Check to see if a user can read a file. This is only approximate,
it is used as part of the "hide unreadable" option. Don't
@@ -807,116 +893,95 @@ static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT
}
/*******************************************************************
- Open a directory.
+ Should the file be seen by the client ?
********************************************************************/
-void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
+BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
{
- Dir *dirp;
- const char *n;
- DIR *p = SMB_VFS_OPENDIR(conn,name);
- int used=0;
+ BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
+ BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
+ BOOL hide_special = lp_hide_special_files(SNUM(conn));
- if (!p)
- return(NULL);
- dirp = SMB_MALLOC_P(Dir);
- if (!dirp) {
- DEBUG(0,("Out of memory in OpenDir\n"));
- SMB_VFS_CLOSEDIR(conn,p);
- return(NULL);
- }
- dirp->pos = dirp->numentries = dirp->mallocsize = 0;
- dirp->data = dirp->current = NULL;
+ ZERO_STRUCTP(pst);
- while (True) {
- int l;
- BOOL normal_entry = True;
- SMB_STRUCT_STAT st;
- char *entry = NULL;
-
- if (used == 0) {
- n = ".";
- normal_entry = False;
- } else if (used == 2) {
- n = "..";
- normal_entry = False;
- } else {
- n = vfs_readdirname(conn, p);
- if (n == NULL)
- break;
- if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
- continue;
- normal_entry = True;
- }
+ if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
+ return True; /* . and .. are always visible. */
+ }
- ZERO_STRUCT(st);
- l = strlen(n)+1;
+ /* If it's a vetoed file, pretend it doesn't even exist */
+ if (use_veto && IS_VETO_PATH(conn, name)) {
+ return False;
+ }
- /* If it's a vetoed file, pretend it doesn't even exist */
- if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
- continue;
+ if (hide_unreadable || hide_unwriteable || hide_special) {
+ char *entry = NULL;
+ if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
+ return False;
+ }
/* Honour _hide unreadable_ option */
- if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
- int ret=0;
-
- if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
- ret = user_can_read_file(conn, entry, &st);
- }
- if (!ret) {
- SAFE_FREE(entry);
- continue;
- }
+ if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
+ SAFE_FREE(entry);
+ return False;
}
-
/* Honour _hide unwriteable_ option */
- if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
- int ret=0;
-
- if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
- ret = user_can_write_file(conn, entry, &st);
- }
- if (!ret) {
- SAFE_FREE(entry);
- continue;
- }
+ if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
+ SAFE_FREE(entry);
+ return False;
}
-
/* Honour _hide_special_ option */
- if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) {
- int ret=0;
-
- if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
- ret = file_is_special(conn, entry, &st);
- }
- if (ret) {
- SAFE_FREE(entry);
- continue;
- }
+ if (hide_special && !file_is_special(conn, entry, pst)) {
+ SAFE_FREE(entry);
+ return False;
}
-
SAFE_FREE(entry);
+ }
+ return True;
+}
- if (used + l > dirp->mallocsize) {
- int s = MAX(used+l,used+2000);
- char *r;
- r = (char *)SMB_REALLOC(dirp->data,s);
- if (!r) {
- DEBUG(0,("Out of memory in OpenDir\n"));
- break;
- }
- dirp->data = r;
- dirp->mallocsize = s;
- dirp->current = dirp->data;
- }
+/*******************************************************************
+ Open a directory.
+********************************************************************/
+
+struct smb_Dir *OpenDir(connection_struct *conn, const char *name)
+{
+ struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
+ if (!dirp) {
+ return NULL;
+ }
+ ZERO_STRUCTP(dirp);
- safe_strcpy_base(dirp->data+used,n, dirp->data, dirp->mallocsize);
- used += l;
- dirp->numentries++;
+ dirp->conn = conn;
+
+ dirp->dir_path = SMB_STRDUP(name);
+ if (!dirp->dir_path) {
+ goto fail;
+ }
+ dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path);
+ if (!dirp->dir) {
+ DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
+ goto fail;
+ }
+
+ dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
+ if (!dirp->name_cache) {
+ goto fail;
}
- SMB_VFS_CLOSEDIR(conn,p);
- return((void *)dirp);
+ dirhandles_open++;
+ return dirp;
+
+ fail:
+
+ if (dirp) {
+ if (dirp->dir) {
+ SMB_VFS_CLOSEDIR(conn,dirp->dir);
+ }
+ SAFE_FREE(dirp->dir_path);
+ SAFE_FREE(dirp->name_cache);
+ SAFE_FREE(dirp);
+ }
+ return NULL;
}
@@ -924,65 +989,110 @@ void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
Close a directory.
********************************************************************/
-void CloseDir(void *p)
+int CloseDir(struct smb_Dir *dirp)
{
- if (!p)
- return;
- SAFE_FREE(((Dir *)p)->data);
- SAFE_FREE(p);
+ int i, ret = 0;
+
+ if (dirp->dir) {
+ ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
+ }
+ SAFE_FREE(dirp->dir_path);
+ if (dirp->name_cache) {
+ for (i = 0; i < NAME_CACHE_SIZE; i++) {
+ SAFE_FREE(dirp->name_cache[i].name);
+ }
+ }
+ SAFE_FREE(dirp->name_cache);
+ SAFE_FREE(dirp);
+ dirhandles_open--;
+ return ret;
}
/*******************************************************************
- Read from a directory.
+ Read from a directory. Also return current offset.
+ Don't check for veto or invisible files.
********************************************************************/
-const char *ReadDirName(void *p)
+const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
{
- char *ret;
- Dir *dirp = (Dir *)p;
-
- if (!dirp || !dirp->current || dirp->pos >= dirp->numentries)
- return(NULL);
-
- ret = dirp->current;
- dirp->current = skip_string(dirp->current,1);
- dirp->pos++;
+ const char *n;
+ connection_struct *conn = dirp->conn;
+
+ SeekDir(dirp, *poffset);
+ while ((n = vfs_readdirname(conn, dirp->dir))) {
+ struct name_cache_entry *e;
+ dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
+ if (dirp->offset == -1) {
+ return NULL;
+ }
+ dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
- return(ret);
+ e = &dirp->name_cache[dirp->name_cache_index];
+ SAFE_FREE(e->name);
+ e->name = SMB_STRDUP(n);
+ *poffset = e->offset= dirp->offset;
+ return e->name;
+ }
+ return NULL;
}
/*******************************************************************
Seek a dir.
********************************************************************/
-BOOL SeekDir(void *p,int pos)
+void SeekDir(struct smb_Dir *dirp, long offset)
{
- Dir *dirp = (Dir *)p;
-
- if (!dirp)
- return(False);
-
- if (pos < dirp->pos) {
- dirp->current = dirp->data;
- dirp->pos = 0;
+ if (offset != dirp->offset) {
+ SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
+ dirp->offset = offset;
}
+}
- while (dirp->pos < pos && ReadDirName(p))
- ;
+/*******************************************************************
+ Tell a dir position.
+********************************************************************/
- return (dirp->pos == pos);
+long TellDir(struct smb_Dir *dirp)
+{
+ return(dirp->offset);
}
/*******************************************************************
- Tell a dir position.
+ Find an entry by name. Leave us at the offset after it.
+ Don't check for veto or invisible files.
********************************************************************/
-int TellDir(void *p)
+BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
{
- Dir *dirp = (Dir *)p;
+ int i;
+ const char *entry;
+ connection_struct *conn = dirp->conn;
+
+ /* Search back in the name cache. */
+ for (i = dirp->name_cache_index; i >= 0; i--) {
+ struct name_cache_entry *e = &dirp->name_cache[i];
+ if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
+ *poffset = e->offset;
+ SeekDir(dirp, e->offset);
+ return True;
+ }
+ }
+ for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
+ struct name_cache_entry *e = &dirp->name_cache[i];
+ if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
+ *poffset = e->offset;
+ SeekDir(dirp, e->offset);
+ return True;
+ }
+ }
- if (!dirp)
- return(-1);
-
- return(dirp->pos);
+ /* Not found in the name cache. Rewind directory and start from scratch. */
+ SMB_VFS_REWINDDIR(conn, dirp->dir);
+ *poffset = 0;
+ while ((entry = ReadDirName(dirp, poffset))) {
+ if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
+ return True;
+ }
+ }
+ return False;
}
diff --git a/source/smbd/filename.c b/source/smbd/filename.c
index 279c9dd3c45..8c484dd232a 100644
--- a/source/smbd/filename.c
+++ b/source/smbd/filename.c
@@ -150,11 +150,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
pstrcpy(saved_last_component, name);
}
-#if 1
if (!conn->case_preserve || (mangle_is_8_3(name, False) && !conn->short_case_preserve))
-#else
- if (!conn->case_sensitive && (!conn->case_preserve || (mangle_is_8_3(name, False) && !conn->short_case_preserve)))
-#endif
strnorm(name, lp_defaultcase(SNUM(conn)));
start = name;
@@ -432,9 +428,10 @@ BOOL check_name(pstring name,connection_struct *conn)
static BOOL scan_directory(connection_struct *conn, const char *path, char *name, size_t maxlength)
{
- void *cur_dir;
+ struct smb_Dir *cur_dir;
const char *dname;
BOOL mangled;
+ long curpos;
mangled = mangle_is_mangled(name);
@@ -453,13 +450,14 @@ static BOOL scan_directory(connection_struct *conn, const char *path, char *name
mangled = !mangle_check_cache( name, maxlength );
/* open the directory */
- if (!(cur_dir = OpenDir(conn, path, True))) {
+ if (!(cur_dir = OpenDir(conn, path))) {
DEBUG(3,("scan dir didn't open dir [%s]\n",path));
return(False);
}
/* now scan for matching names */
- while ((dname = ReadDirName(cur_dir))) {
+ curpos = 0;
+ while ((dname = ReadDirName(cur_dir, &curpos))) {
/* Is it dot or dot dot. */
if ((dname[0] == '.') && (!dname[1] || (dname[1] == '.' && !dname[2]))) {
diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c
index 843580f6edf..b16b7677833 100644
--- a/source/smbd/notify_hash.c
+++ b/source/smbd/notify_hash.c
@@ -44,7 +44,8 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
const char *fname;
size_t remaining_len;
size_t fullname_len;
- void *dp;
+ struct smb_Dir *dp;
+ long offset;
ZERO_STRUCTP(data);
@@ -75,7 +76,7 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
* larger than the max time_t value).
*/
- dp = OpenDir(conn, path, True);
+ dp = OpenDir(conn, path);
if (dp == NULL)
return False;
@@ -88,19 +89,24 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
remaining_len = sizeof(full_name) - fullname_len - 1;
p = &full_name[fullname_len];
- while ((fname = ReadDirName(dp))) {
+ offset = 0;
+ while ((fname = ReadDirName(dp, &offset))) {
+ ZERO_STRUCT(st);
if(strequal(fname, ".") || strequal(fname, ".."))
continue;
+ if (!is_visible_file(conn, path, fname, &st, True))
+ continue;
+
data->num_entries++;
safe_strcpy(p, fname, remaining_len);
- ZERO_STRUCT(st);
-
/*
* Do the stat - but ignore errors.
*/
- SMB_VFS_STAT(conn,full_name, &st);
+ if (!VALID_STAT(st)) {
+ SMB_VFS_STAT(conn,full_name, &st);
+ }
/*
* Always sum the times.
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index 2395d0d8db5..675da4c7478 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -780,6 +780,27 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
}
}
+#if 0
+ /* This is the correct thing to do (check every time) but can_delete is
+ expensive (it may have to read the parent directory permissions). So
+ for now we're not doing it unless we have a strong hint the client
+ is really going to delete this file. */
+ if (desired_access & DELETE_ACCESS) {
+#else
+ /* Setting FILE_SHARE_DELETE is the hint. */
+ if ((share_access & FILE_SHARE_DELETE) && (desired_access & DELETE_ACCESS)) {
+#endif
+ status = can_delete(conn, fname, file_attributes, bad_path, True);
+ /* We're only going to fail here if it's access denied, as that's the
+ only error we care about for "can we delete this ?" questions. */
+ if (!NT_STATUS_IS_OK(status) && (NT_STATUS_EQUAL(status,NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_CANNOT_DELETE))) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(status);
+ }
+ }
+
/*
* If it's a request for a directory open, deal with it separately.
*/
@@ -908,7 +929,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
allocation_size |= (((SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize + 4)) << 32);
#endif
if (allocation_size && (allocation_size > (SMB_BIG_UINT)file_len)) {
- fsp->initial_allocation_size = smb_roundup(allocation_size);
+ fsp->initial_allocation_size = allocation_size;
if (fsp->is_directory) {
close_file(fsp,False);
END_PROFILE(SMBntcreateX);
@@ -921,7 +942,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib
return ERROR_NT(NT_STATUS_DISK_FULL);
}
} else {
- fsp->initial_allocation_size = smb_roundup((SMB_BIG_UINT)file_len);
+ fsp->initial_allocation_size = (SMB_BIG_UINT)file_len;
}
/*
@@ -1319,6 +1340,27 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
+#if 0
+ /* This is the correct thing to do (check every time) but can_delete is
+ expensive (it may have to read the parent directory permissions). So
+ for now we're not doing it unless we have a strong hint the client
+ is really going to delete this file. */
+ if (desired_access & DELETE_ACCESS) {
+#else
+ /* Setting FILE_SHARE_DELETE is the hint. */
+ if ((share_access & FILE_SHARE_DELETE) && (desired_access & DELETE_ACCESS)) {
+#endif
+ status = can_delete(conn, fname, file_attributes, bad_path, True);
+ /* We're only going to fail here if it's access denied, as that's the
+ only error we care about for "can we delete this ?" questions. */
+ if (!NT_STATUS_IS_OK(status) && (NT_STATUS_EQUAL(status,NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_CANNOT_DELETE))) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(status);
+ }
+ }
+
/*
* If it's a request for a directory open, deal with it separately.
*/
@@ -1430,7 +1472,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32);
#endif
if (allocation_size && (allocation_size > file_len)) {
- fsp->initial_allocation_size = smb_roundup(allocation_size);
+ fsp->initial_allocation_size = allocation_size;
if (fsp->is_directory) {
close_file(fsp,False);
END_PROFILE(SMBntcreateX);
@@ -1442,7 +1484,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
return ERROR_NT(NT_STATUS_DISK_FULL);
}
} else {
- fsp->initial_allocation_size = smb_roundup((SMB_BIG_UINT)file_len);
+ fsp->initial_allocation_size = (SMB_BIG_UINT)file_len;
}
/* Realloc the size of parameters and data we will return */
@@ -2143,6 +2185,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
shadow_data = TALLOC_ZERO_P(shadow_mem_ctx,SHADOW_COPY_DATA);
if (shadow_data == NULL) {
DEBUG(0,("talloc_zero() failed!\n"));
+ talloc_destroy(shadow_mem_ctx);
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
@@ -2310,7 +2353,7 @@ static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf,
/* access check */
if (current_user.uid != 0) {
- DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n",
+ DEBUG(1,("get_user_quota: access_denied service [%s] user [%s]\n",
lp_servicename(SNUM(conn)),conn->user));
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
index 903b9435225..d02edc5ea06 100644
--- a/source/smbd/posix_acls.c
+++ b/source/smbd/posix_acls.c
@@ -3753,3 +3753,160 @@ BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *
SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
return True;
}
+
+/****************************************************************************
+ Check for POSIX group ACLs. If none use stat entry.
+****************************************************************************/
+
+static int check_posix_acl_group_write(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *psbuf)
+{
+ extern struct current_user current_user;
+ SMB_ACL_T posix_acl = NULL;
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+ SMB_ACL_ENTRY_T entry;
+ int i;
+ int ret = -1;
+
+ if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, dname, SMB_ACL_TYPE_ACCESS)) == NULL) {
+ goto check_stat;
+ }
+
+ /* First ensure the group mask allows group read. */
+ while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_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) {
+ goto check_stat;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ goto check_stat;
+ }
+
+ switch(tagtype) {
+ case SMB_ACL_MASK:
+ if (!SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE)) {
+ /* We don't have group write permission. */
+ ret = -1; /* Allow caller to check "other" permissions. */
+ goto done;
+ }
+ break;
+ default:
+ continue;
+ }
+ }
+
+ /* Now check all group entries. */
+ entry_id = SMB_ACL_FIRST_ENTRY;
+ while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+ int have_write = -1;
+
+ /* 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) {
+ goto check_stat;
+ }
+
+ if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ goto check_stat;
+ }
+
+ have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
+ if (have_write == -1) {
+ goto check_stat;
+ }
+
+ switch(tagtype) {
+ case SMB_ACL_USER:
+ {
+ /* Check against current_user.uid. */
+ uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ if (puid == NULL) {
+ goto check_stat;
+ }
+ if (current_user.uid == *puid) {
+ /* We're done now we have a uid match. */
+ ret = have_write;
+ goto done;
+ }
+ }
+ break;
+ case SMB_ACL_MASK:
+ {
+ gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ if (pgid == NULL) {
+ goto check_stat;
+ }
+ for (i = 0; i < current_user.ngroups; i++) {
+ if (current_user.groups[i] == *pgid) {
+ /* We're done now we have a gid match. */
+ ret = have_write;
+ goto done;
+ }
+ }
+ }
+ break;
+ default:
+ continue;
+ }
+ }
+
+
+ check_stat:
+
+ for (i = 0; i < current_user.ngroups; i++) {
+ if (current_user.groups[i] == psbuf->st_gid) {
+ ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
+ break;
+ }
+ }
+
+ done:
+
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ return ret;
+}
+
+/****************************************************************************
+ Actually emulate the in-kernel access checking for write access. We need
+ this to successfully return ACCESS_DENIED on a file open for delete access.
+****************************************************************************/
+
+BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
+{
+ extern struct current_user current_user;
+ SMB_STRUCT_STAT sbuf;
+ pstring dname;
+ int ret;
+
+ pstrcpy(dname, parent_dirname(fname));
+ if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
+ return False;
+ }
+ if (!S_ISDIR(sbuf.st_mode)) {
+ return False;
+ }
+ if (current_user.uid == 0) {
+ /* I'm sorry sir, I didn't know you were root... */
+ return True;
+ }
+
+ if (current_user.uid == sbuf.st_uid) {
+ return (sbuf.st_mode & S_IWUSR) ? True : False;
+ }
+ /* Check group ownership. */
+ ret = check_posix_acl_group_write(conn, dname, &sbuf);
+ if (ret == 0 || ret == 1) {
+ return ret ? True : False;
+ }
+ return (sbuf.st_mode & S_IWOTH) ? True : False;
+}
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 26a0c9e7a9b..89183aed347 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -899,8 +899,10 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
END_PROFILE(SMBsearch);
return ERROR_DOS(ERRDOS,ERRnofids);
}
- dptr_set_wcard(dptr_num, SMB_STRDUP(mask));
- dptr_set_attr(dptr_num, dirtype);
+ if (!dptr_set_wcard_and_attributes(dptr_num, mask, dirtype)) {
+ END_PROFILE(SMBsearch);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
} else {
dirtype = dptr_attr(dptr_num);
}
@@ -910,7 +912,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (ok) {
if ((dirtype&0x1F) == aVOLID) {
memcpy(p,status,21);
- make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0,conn->case_sensitive);
+ 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;
@@ -930,7 +932,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
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,conn->case_sensitive);
+ make_dir_struct(p,mask,fname,size,mode,date);
dptr_fill(p+12,dptr_num);
numentries++;
p += DIR_STRUCT_SIZE;
@@ -947,18 +949,21 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
and no entries were found then return error and close dirptr
(X/Open spec) */
- if(ok && expect_close && numentries == 0 && status_len == 0) {
- /* Close the dptr - we know it's gone */
+ if (numentries == 0 || !ok) {
dptr_close(&dptr_num);
- return ERROR_BOTH(STATUS_NO_MORE_FILES,ERRDOS,ERRnofiles);
- } else if (numentries == 0 || !ok) {
+ } else if(ok && expect_close && status_len == 0) {
+ /* Close the dptr - we know it's gone */
dptr_close(&dptr_num);
- return ERROR_BOTH(STATUS_NO_MORE_FILES,ERRDOS,ERRnofiles);
}
/* If we were called as SMBfunique, then we can close the dirptr now ! */
- if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
+ if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique) {
dptr_close(&dptr_num);
+ }
+
+ if ((numentries == 0) && !ms_has_wild(mask)) {
+ return ERROR_BOTH(STATUS_NO_MORE_FILES,ERRDOS,ERRnofiles);
+ }
SSVAL(outbuf,smb_vwv0,numentries);
SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
@@ -1433,7 +1438,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
Check if a user is allowed to rename a file.
********************************************************************/
-static NTSTATUS can_rename(char *fname,connection_struct *conn, uint16 dirtype, SMB_STRUCT_STAT *pst)
+static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst)
{
int smb_action;
int access_mode;
@@ -1474,7 +1479,7 @@ static NTSTATUS can_rename(char *fname,connection_struct *conn, uint16 dirtype,
Check if a user is allowed to delete a file.
********************************************************************/
-static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype, BOOL bad_path)
+NTSTATUS can_delete(connection_struct *conn, char *fname, int dirtype, BOOL bad_path, BOOL check_is_at_open)
{
SMB_STRUCT_STAT sbuf;
int fmode;
@@ -1515,25 +1520,34 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype, BOO
if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
return NT_STATUS_NO_SUCH_FILE;
- /* We need a better way to return NT status codes from open... */
- unix_ERR_class = 0;
- unix_ERR_code = 0;
-
- fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
- (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
+ if (check_is_at_open) {
+ if (!can_delete_file_in_directory(conn, fname)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else {
+ /* On open checks the open itself will check the share mode, so
+ don't do it here as we'll get it wrong. */
- if (!fsp) {
- NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
- if (!NT_STATUS_IS_OK(unix_ERR_ntstatus))
- ret = unix_ERR_ntstatus;
- else if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
- ret = NT_STATUS_SHARING_VIOLATION;
+ /* We need a better way to return NT status codes from open... */
unix_ERR_class = 0;
unix_ERR_code = 0;
- unix_ERR_ntstatus = NT_STATUS_OK;
- return ret;
+
+ fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
+ (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
+
+ if (!fsp) {
+ NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
+ if (!NT_STATUS_IS_OK(unix_ERR_ntstatus))
+ ret = unix_ERR_ntstatus;
+ else if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
+ ret = NT_STATUS_SHARING_VIOLATION;
+ unix_ERR_class = 0;
+ unix_ERR_code = 0;
+ unix_ERR_ntstatus = NT_STATUS_OK;
+ return ret;
+ }
+ close_file(fsp,False);
}
- close_file(fsp,False);
return NT_STATUS_OK;
}
@@ -1593,7 +1607,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
if (!has_wild) {
pstrcat(directory,"/");
pstrcat(directory,mask);
- error = can_delete(directory,conn,dirtype,bad_path);
+ error = can_delete(conn,directory,dirtype,bad_path,False);
if (!NT_STATUS_IS_OK(error))
return error;
@@ -1601,28 +1615,34 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
count++;
}
} else {
- void *dirptr = NULL;
+ struct smb_Dir *dir_hnd = NULL;
const char *dname;
if (check_name(directory,conn))
- dirptr = OpenDir(conn, directory, True);
+ dir_hnd = OpenDir(conn, directory);
/* 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) {
+ if (dir_hnd) {
+ long offset = 0;
error = NT_STATUS_NO_SUCH_FILE;
-
+
if (strequal(mask,"????????.???"))
pstrcpy(mask,"*");
- while ((dname = ReadDirName(dirptr))) {
+ while ((dname = ReadDirName(dir_hnd, &offset))) {
+ SMB_STRUCT_STAT st;
pstring fname;
BOOL sys_direntry = False;
pstrcpy(fname,dname);
+ if (!is_visible_file(conn, directory, dname, &st, True)) {
+ continue;
+ }
+
/* Quick check for "." and ".." */
if (fname[0] == '.') {
if (!fname[1] || (fname[1] == '.' && !fname[2])) {
@@ -1645,7 +1665,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
}
slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
- error = can_delete(fname,conn,dirtype,bad_path);
+ error = can_delete(conn,fname,dirtype,bad_path,False);
if (!NT_STATUS_IS_OK(error)) {
continue;
}
@@ -1653,7 +1673,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
count++;
DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
}
- CloseDir(dirptr);
+ CloseDir(dir_hnd);
}
}
@@ -3361,18 +3381,22 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
{
const char *dname = NULL;
BOOL ret = False;
- void *dirptr = OpenDir(conn, directory, False);
+ long offset = 0;
+ struct smb_Dir *dir_hnd = OpenDir(conn, directory);
- if(dirptr == NULL)
+ if(dir_hnd == NULL)
return True;
- while((dname = ReadDirName(dirptr))) {
+ while((dname = ReadDirName(dir_hnd, &offset))) {
pstring fullname;
SMB_STRUCT_STAT st;
if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
continue;
+ if (!is_visible_file(conn, directory, dname, &st, False))
+ continue;
+
/* Construct the full name. */
if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
errno = ENOMEM;
@@ -3403,7 +3427,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
break;
}
}
- CloseDir(dirptr);
+ CloseDir(dir_hnd);
return ret;
}
@@ -3414,6 +3438,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
BOOL rmdir_internals(connection_struct *conn, char *directory)
{
BOOL ok;
+ SMB_STRUCT_STAT st;
ok = (SMB_VFS_RMDIR(conn,directory) == 0);
if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
@@ -3425,13 +3450,15 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
*/
BOOL all_veto_files = True;
const char *dname;
- void *dirptr = OpenDir(conn, directory, False);
+ struct smb_Dir *dir_hnd = OpenDir(conn, directory);
- if(dirptr != NULL) {
- int dirpos = TellDir(dirptr);
- while ((dname = ReadDirName(dirptr))) {
+ if(dir_hnd != NULL) {
+ long dirpos = TellDir(dir_hnd);
+ while ((dname = ReadDirName(dir_hnd,&dirpos))) {
if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
continue;
+ if (!is_visible_file(conn, directory, dname, &st, False))
+ continue;
if(!IS_VETO_PATH(conn, dname)) {
all_veto_files = False;
break;
@@ -3439,13 +3466,14 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
}
if(all_veto_files) {
- SeekDir(dirptr,dirpos);
- while ((dname = ReadDirName(dirptr))) {
+ SeekDir(dir_hnd,dirpos);
+ while ((dname = ReadDirName(dir_hnd,&dirpos))) {
pstring fullname;
- SMB_STRUCT_STAT st;
if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
continue;
+ if (!is_visible_file(conn, directory, dname, &st, False))
+ continue;
/* Construct the full name. */
if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
@@ -3469,11 +3497,11 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
} else if(SMB_VFS_UNLINK(conn,fullname) != 0)
break;
}
- CloseDir(dirptr);
+ CloseDir(dir_hnd);
/* Retry the rmdir */
ok = (SMB_VFS_RMDIR(conn,directory) == 0);
} else {
- CloseDir(dirptr);
+ CloseDir(dir_hnd);
}
} else {
errno = ENOTEMPTY;
@@ -3725,7 +3753,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
return NT_STATUS_OBJECT_NAME_COLLISION;
}
- error = can_rename(newname,conn,attrs,&sbuf);
+ error = can_rename(conn,newname,attrs,&sbuf);
if (dest_exists && !NT_STATUS_IS_OK(error)) {
DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
@@ -3931,7 +3959,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
}
- error = can_rename(directory,conn,attrs,&sbuf1);
+ error = can_rename(conn,directory,attrs,&sbuf1);
if (!NT_STATUS_IS_OK(error)) {
DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
@@ -3976,21 +4004,22 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
/*
* Wildcards - process each file that matches.
*/
- void *dirptr = NULL;
+ struct smb_Dir *dir_hnd = NULL;
const char *dname;
pstring destname;
if (check_name(directory,conn))
- dirptr = OpenDir(conn, directory, True);
+ dir_hnd = OpenDir(conn, directory);
- if (dirptr) {
+ if (dir_hnd) {
+ long offset = 0;
error = NT_STATUS_NO_SUCH_FILE;
/* Was error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */
if (strequal(mask,"????????.???"))
pstrcpy(mask,"*");
- while ((dname = ReadDirName(dirptr))) {
+ while ((dname = ReadDirName(dir_hnd, &offset))) {
pstring fname;
BOOL sysdir_entry = False;
@@ -4007,6 +4036,9 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
}
}
+ if (!is_visible_file(conn, directory, dname, &sbuf1, False))
+ continue;
+
if(!mask_match(fname, mask, conn->case_sensitive))
continue;
@@ -4022,7 +4054,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error)));
continue;
}
- error = can_rename(fname,conn,attrs,&sbuf1);
+ error = can_rename(conn,fname,attrs,&sbuf1);
if (!NT_STATUS_IS_OK(error)) {
DEBUG(6,("rename %s refused\n", fname));
continue;
@@ -4057,7 +4089,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
}
DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
}
- CloseDir(dirptr);
+ CloseDir(dir_hnd);
}
if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) {
@@ -4329,23 +4361,27 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
exists = vfs_file_exist(conn,directory,NULL);
}
} else {
- void *dirptr = NULL;
+ struct smb_Dir *dir_hnd = NULL;
const char *dname;
pstring destname;
if (check_name(directory,conn))
- dirptr = OpenDir(conn, directory, True);
+ dir_hnd = OpenDir(conn, directory);
- if (dirptr) {
+ if (dir_hnd) {
+ long offset = 0;
error = ERRbadfile;
if (strequal(mask,"????????.???"))
pstrcpy(mask,"*");
- while ((dname = ReadDirName(dirptr))) {
+ while ((dname = ReadDirName(dir_hnd, &offset))) {
pstring fname;
pstrcpy(fname,dname);
+ if (!is_visible_file(conn, directory, dname, &sbuf1, False))
+ continue;
+
if(!mask_match(fname, mask, conn->case_sensitive))
continue;
@@ -4358,7 +4394,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
count++;
DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
}
- CloseDir(dirptr);
+ CloseDir(dir_hnd);
}
}
diff --git a/source/smbd/service.c b/source/smbd/service.c
index 2e60adc6366..f199fe3ade6 100644
--- a/source/smbd/service.c
+++ b/source/smbd/service.c
@@ -60,17 +60,26 @@ BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
last_flags = flags;
/* Obey the client case sensitivity requests - only for clients that support it. */
- if (lp_casesensitive(snum) == Auto) {
- /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
- enum remote_arch_types ra_type = get_remote_arch();
- if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
- /* Client can't support per-packet case sensitive pathnames. */
+ switch (lp_casesensitive(snum)) {
+ case Auto:
+ {
+ /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
+ enum remote_arch_types ra_type = get_remote_arch();
+ if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
+ /* Client can't support per-packet case sensitive pathnames. */
+ conn->case_sensitive = False;
+ } else {
+ conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
+ }
+ }
+ break;
+ case True:
+ conn->case_sensitive = True;
+ break;
+ default:
conn->case_sensitive = False;
- } else {
- conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
- }
+ break;
}
-
magic_char = lp_magicchar(snum);
return(True);
}
diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c
index cff7d7371c6..40ea28a86d5 100644
--- a/source/smbd/sesssetup.c
+++ b/source/smbd/sesssetup.c
@@ -755,10 +755,18 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
pstring pass;
BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
+#if 0
+ /* This was the previous fix. Not sure if it's still valid. JRA. */
if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
/* NT4.0 stuffs up plaintext unicode password lengths... */
srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
sizeof(pass), passlen1, STR_TERMINATE);
+#endif
+
+ if (unic && (passlen2 == 0) && passlen1) {
+ /* Only a ascii plaintext password was sent. */
+ srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
+ passlen1, STR_TERMINATE|STR_ASCII);
} else {
srvstr_pull(inbuf, pass, smb_buf(inbuf),
sizeof(pass), unic ? passlen2 : passlen1,
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index a15a89bb766..d22705214e4 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -33,21 +33,6 @@ extern struct current_user current_user;
#define DIR_ENTRY_SAFETY_MARGIN 4096
/********************************************************************
- Roundup a value to the nearest SMB_ROUNDUP_ALLOCATION_SIZE boundary.
- Only do this for Windows clients.
-********************************************************************/
-
-SMB_BIG_UINT smb_roundup(SMB_BIG_UINT val)
-{
- /* Only roundup for Windows clients. */
- enum remote_arch_types ra_type = get_remote_arch();
- if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
- val = SMB_ROUNDUP(val,SMB_ROUNDUP_ALLOCATION_SIZE);
- }
- return val;
-}
-
-/********************************************************************
Given a stat buffer return the allocated size on disk, taking into
account sparse files.
********************************************************************/
@@ -65,8 +50,6 @@ SMB_BIG_UINT get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf)
if (!ret && fsp && fsp->initial_allocation_size)
ret = fsp->initial_allocation_size;
- ret = smb_roundup(ret);
-
return ret;
}
@@ -801,21 +784,6 @@ static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *ps
}
/****************************************************************************
- Checks for SMB_TIME_NO_CHANGE and if not found calls interpret_long_date.
-****************************************************************************/
-
-time_t interpret_long_unix_date(char *p)
-{
- DEBUG(10,("interpret_long_unix_date\n"));
- if(IVAL(p,0) == SMB_TIME_NO_CHANGE_LO &&
- IVAL(p,4) == SMB_TIME_NO_CHANGE_HI) {
- return -1;
- } else {
- return interpret_long_date(p);
- }
-}
-
-/****************************************************************************
Get a level dependent lanman2 dir entry.
****************************************************************************/
@@ -836,7 +804,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
pstring fname;
char *p, *q, *pdata = *ppdata;
uint32 reskey=0;
- int prev_dirpos=0;
+ long prev_dirpos=0;
int mode=0;
SMB_OFF_T file_size = 0;
SMB_BIG_UINT allocation_size = 0;
@@ -863,12 +831,12 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
} else
pstrcpy(mask, path_mask);
+
while (!found) {
BOOL got_match;
-
/* Needed if we run out of space */
- prev_dirpos = TellDir(conn->dirptr);
- dname = ReadDirName(conn->dirptr);
+ long curr_dirpos = prev_dirpos = dptr_TellDir(conn->dirptr);
+ dname = dptr_ReadDirName(conn->dirptr,&curr_dirpos,&sbuf);
/*
* Due to bugs in NT client redirectors we are not using
@@ -879,8 +847,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
reskey = 0;
- DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
- (long)conn->dirptr,TellDir(conn->dirptr)));
+ DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %ld\n",
+ (long)conn->dirptr,curr_dirpos));
if (!dname)
return(False);
@@ -922,7 +890,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
pathreal,strerror(errno)));
continue;
}
- } else if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+ } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
/* Needed to show the msdfs symlinks as
* directories */
@@ -945,7 +913,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
mode = dos_mode(conn,pathreal,&sbuf);
- if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+ if (!dir_check_ftype(conn,mode,dirtype)) {
DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
continue;
}
@@ -1303,7 +1271,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
if (PTR_DIFF(p,pdata) > space_remaining) {
/* Move the dirptr back to prev_dirpos */
- SeekDir(conn->dirptr, prev_dirpos);
+ dptr_SeekDir(conn->dirptr, prev_dirpos);
*out_of_space = True;
DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
return False; /* Not finished - just out of space */
@@ -1341,7 +1309,7 @@ static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outb
int info_level = SVAL(params,6);
pstring directory;
pstring mask;
- char *p, *wcard;
+ char *p;
int last_name_off=0;
int dptr_num = -1;
int numentries = 0;
@@ -1437,15 +1405,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
/* Save the wildcard match and attribs we are using on this directory -
needed as lanman2 assumes these are being saved between calls */
- if(!(wcard = SMB_STRDUP(mask))) {
+ if (!dptr_set_wcard_and_attributes(dptr_num, mask, dirtype)) {
dptr_close(&dptr_num);
return ERROR_DOS(ERRDOS,ERRnomem);
}
- dptr_set_wcard(dptr_num, wcard);
- dptr_set_attr(dptr_num, dirtype);
-
- DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
+ DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, mask, dirtype));
/* We don't need to check for VOL here as this is returned by
a different TRANS2 call. */
@@ -1648,10 +1613,10 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
/* Get the attr mask from the dptr */
dirtype = dptr_attr(dptr_num);
- DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n",
+ DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n",
dptr_num, mask, dirtype,
(long)conn->dirptr,
- TellDir(conn->dirptr)));
+ dptr_TellDir(conn->dirptr)));
/* We don't need to check for VOL here as this is returned by
a different TRANS2 call. */
@@ -1670,84 +1635,29 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
*/
if(*resume_name && !continue_bit) {
+ SMB_STRUCT_STAT st;
+ long current_pos = 0;
/*
- * Fix for NT redirector problem triggered by resume key indexes
- * changing between directory scans. We now return a resume key of 0
- * and instead look for the filename to continue from (also given
- * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
- * findfirst/findnext (as is usual) then the directory pointer
- * should already be at the correct place. Check this by scanning
- * backwards looking for an exact (ie. case sensitive) filename match.
- * If we get to the beginning of the directory and haven't found it then scan
- * forwards again looking for a match. JRA.
+ * Remember, mangle_map is called by
+ * get_lanman2_dir_entry(), so the resume name
+ * could be mangled. Ensure we check the unmangled name.
*/
- int current_pos, start_pos;
- const char *dname = NULL;
- pstring dname_pstring;
- void *dirptr = conn->dirptr;
- start_pos = TellDir(dirptr);
- for(current_pos = start_pos; current_pos >= 0; current_pos--) {
- DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos));
-
- SeekDir(dirptr, current_pos);
- dname = ReadDirName(dirptr);
- if (dname) {
- /*
- * Remember, mangle_map is called by
- * get_lanman2_dir_entry(), so the resume name
- * could be mangled. Ensure we do the same
- * here.
- */
-
- /* make sure we get a copy that mangle_map can modify */
-
- pstrcpy(dname_pstring, dname);
- mangle_map( dname_pstring, False, True, SNUM(conn));
-
- if(strcsequal( resume_name, dname_pstring)) {
- SeekDir(dirptr, current_pos+1);
- DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
- break;
- }
- }
+ if (mangle_is_mangled(resume_name)) {
+ mangle_check_cache(resume_name, sizeof(resume_name)-1);
}
/*
- * Scan forward from start if not found going backwards.
+ * Fix for NT redirector problem triggered by resume key indexes
+ * changing between directory scans. We now return a resume key of 0
+ * and instead look for the filename to continue from (also given
+ * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
+ * findfirst/findnext (as is usual) then the directory pointer
+ * should already be at the correct place.
*/
- if(current_pos < 0) {
- DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
- SeekDir(dirptr, start_pos);
- for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; ++current_pos) {
-
- /*
- * Remember, mangle_map is called by
- * get_lanman2_dir_entry(), so the resume name
- * could be mangled. Ensure we do the same
- * here.
- */
-
- if(dname) {
- /* make sure we get a copy that mangle_map can modify */
-
- pstrcpy(dname_pstring, dname);
- mangle_map(dname_pstring, False, True, SNUM(conn));
-
- if(strcsequal( resume_name, dname_pstring)) {
- SeekDir(dirptr, current_pos+1);
- DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
- break;
- }
- }
- } /* end for */
- } /* end if current_pos */
- /* Can't find the name. Just resume from where we were... */
- if (dname == 0) {
- SeekDir(dirptr, start_pos);
- }
+ finished = !dptr_SearchDir(conn->dirptr, resume_name, &current_pos, &st);
} /* end if resume_name && !continue_bit */
for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
@@ -2249,6 +2159,7 @@ int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint
return UNIXERROR(def_class,def_code);
}
+#if defined(HAVE_POSIX_ACLS)
/****************************************************************************
Utility function to count the number of entries in a POSIX acl.
****************************************************************************/
@@ -2363,6 +2274,7 @@ static BOOL marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_
return True;
}
+#endif
/****************************************************************************
Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
@@ -2928,6 +2840,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
break;
}
+#if defined(HAVE_POSIX_ACLS)
case SMB_QUERY_POSIX_ACL:
{
SMB_ACL_T file_acl = NULL;
@@ -3004,6 +2917,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
break;
}
+#endif
default:
return ERROR_DOS(ERRDOS,ERRunknownlevel);
@@ -3027,10 +2941,12 @@ NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close, u
* Only allow delete on close for writable files.
*/
- if (dosmode & aRONLY) {
- DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but file attribute is readonly.\n",
- fsp->fsp_name ));
- return NT_STATUS_CANNOT_DELETE;
+ if (!lp_delete_readonly(SNUM(fsp->conn))) {
+ if (dosmode & aRONLY) {
+ DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but file attribute is readonly.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_CANNOT_DELETE;
+ }
}
/*
@@ -3385,7 +3301,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
tvs.modtime = MIN(write_time, changed_time);
- if (write_time > tvs.modtime && write_time != 0xffffffff) {
+ if (write_time > tvs.modtime && write_time != (time_t)-1) {
tvs.modtime = write_time;
}
/* Prefer a defined time to an undefined one. */
@@ -3417,9 +3333,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
fname, (double)allocation_size ));
- if (allocation_size)
- allocation_size = smb_roundup(allocation_size);
-
if(allocation_size != get_file_size(sbuf)) {
SMB_STRUCT_STAT new_sbuf;
@@ -3564,8 +3477,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
#endif /* LARGE_SMB_OFF_T */
}
pdata+=24; /* ctime & st_blocks are not changed */
- tvs.actime = interpret_long_unix_date(pdata); /* access_time */
- tvs.modtime = interpret_long_unix_date(pdata+8); /* modification_time */
+ tvs.actime = interpret_long_date(pdata); /* access_time */
+ tvs.modtime = interpret_long_date(pdata+8); /* modification_time */
pdata+=16;
set_owner = (uid_t)IVAL(pdata,0);
pdata += 8;
@@ -3813,6 +3726,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
return(-1);
}
+#if defined(HAVE_POSIX_ACLS)
case SMB_SET_POSIX_ACL:
{
uint16 posix_acl_version;
@@ -3862,6 +3776,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
return(-1);
}
+#endif
default:
return ERROR_DOS(ERRDOS,ERRunknownlevel);