#include "smbd/globals.h"
#include "libcli/security/security.h"
#include "lib/util/bitmap.h"
+#include "../lib/util/memcache.h"
/*
This module implements directory related functions for Samba.
#define START_OF_DIRECTORY_OFFSET ((long)0)
#define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
+/* "Special" directory offsets in 32-bit wire format. */
+#define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
+#define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
+#define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
+
/* Make directory handle internals available. */
struct name_cache_entry {
bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
bool did_stat; /* Optimisation for non-wcard searches. */
bool priv; /* Directory handle opened with privilege. */
+ uint32_t counter;
+ struct memcache *dptr_cache;
};
static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
if (dptr->dir_hnd) {
DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
TALLOC_FREE(dptr->dir_hnd);
+ TALLOC_FREE(dptr->dptr_cache);
+ dptr->counter = 0;
}
}
Return the next visible file name, skipping veto'd and invisible files.
****************************************************************************/
-char *dptr_ReadDirName(TALLOC_CTX *ctx,
- struct dptr_struct *dptr,
- long *poffset,
- SMB_STRUCT_STAT *pst)
+static char *dptr_ReadDirName(TALLOC_CTX *ctx,
+ struct dptr_struct *dptr,
+ long *poffset,
+ SMB_STRUCT_STAT *pst)
{
struct smb_filename smb_fname_base;
char *name = NULL;
SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
}
+/****************************************************************************
+ Map a native directory offset to a 32-bit cookie.
+****************************************************************************/
+
+static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
+{
+ DATA_BLOB key;
+ DATA_BLOB val;
+
+ if (offset == END_OF_DIRECTORY_OFFSET) {
+ return WIRE_END_OF_DIRECTORY_OFFSET;
+ } else if(offset == START_OF_DIRECTORY_OFFSET) {
+ return WIRE_START_OF_DIRECTORY_OFFSET;
+ } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
+ return WIRE_DOT_DOT_DIRECTORY_OFFSET;
+ }
+ if (sizeof(long) == 4) {
+ /* 32-bit machine. We can cheat... */
+ return (uint32_t)offset;
+ }
+ if (dptr->dptr_cache == NULL) {
+ /* Lazy initialize cache. */
+ dptr->dptr_cache = memcache_init(dptr, 0);
+ if (dptr->dptr_cache == NULL) {
+ return WIRE_END_OF_DIRECTORY_OFFSET;
+ }
+ } else {
+ /* Have we seen this offset before ? */
+ key.data = (void *)&offset;
+ key.length = sizeof(offset);
+ if (memcache_lookup(dptr->dptr_cache,
+ SMB1_SEARCH_OFFSET_MAP,
+ key,
+ &val)) {
+ uint32_t wire_offset;
+ SMB_ASSERT(val.length == sizeof(wire_offset));
+ memcpy(&wire_offset, val.data, sizeof(wire_offset));
+ DEBUG(10,("found wire %u <-> offset %ld\n",
+ (unsigned int)wire_offset,
+ (long)offset));
+ return wire_offset;
+ }
+ }
+ /* Allocate a new wire cookie. */
+ do {
+ dptr->counter++;
+ } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
+ dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
+ dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
+ /* Store it in the cache. */
+ key.data = (void *)&offset;
+ key.length = sizeof(offset);
+ val.data = (void *)&dptr->counter;
+ val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
+ memcache_add(dptr->dptr_cache,
+ SMB1_SEARCH_OFFSET_MAP,
+ key,
+ val);
+ /* And the reverse mapping for lookup from
+ map_wire_to_dir_offset(). */
+ memcache_add(dptr->dptr_cache,
+ SMB1_SEARCH_OFFSET_MAP,
+ val,
+ key);
+ DEBUG(10,("stored wire %u <-> offset %ld\n",
+ (unsigned int)dptr->counter,
+ (long)offset));
+ return dptr->counter;
+}
+
/****************************************************************************
Fill the 5 byte server reserved dptr field.
****************************************************************************/
{
unsigned char *buf = (unsigned char *)buf1;
struct dptr_struct *dptr = dptr_get(sconn, key, false);
- uint32 offset;
+ uint32_t wire_offset;
if (!dptr) {
DEBUG(1,("filling null dirptr %d\n",key));
return(False);
}
- offset = (uint32)TellDir(dptr->dir_hnd);
+ wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
- (long)dptr->dir_hnd,(int)offset));
+ (long)dptr->dir_hnd,(int)wire_offset));
buf[0] = key;
- SIVAL(buf,1,offset);
+ SIVAL(buf,1,wire_offset);
return(True);
}
+/****************************************************************************
+ Map a 32-bit wire cookie to a native directory offset.
+****************************************************************************/
+
+static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
+{
+ DATA_BLOB key;
+ DATA_BLOB val;
+
+ if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
+ return END_OF_DIRECTORY_OFFSET;
+ } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
+ return START_OF_DIRECTORY_OFFSET;
+ } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
+ return DOT_DOT_DIRECTORY_OFFSET;
+ }
+ if (sizeof(long) == 4) {
+ /* 32-bit machine. We can cheat... */
+ return (long)wire_offset;
+ }
+ if (dptr->dptr_cache == NULL) {
+ /* Logic error, cache should be initialized. */
+ return END_OF_DIRECTORY_OFFSET;
+ }
+ key.data = (void *)&wire_offset;
+ key.length = sizeof(wire_offset);
+ if (memcache_lookup(dptr->dptr_cache,
+ SMB1_SEARCH_OFFSET_MAP,
+ key,
+ &val)) {
+ /* Found mapping. */
+ long offset;
+ SMB_ASSERT(val.length == sizeof(offset));
+ memcpy(&offset, val.data, sizeof(offset));
+ DEBUG(10,("lookup wire %u <-> offset %ld\n",
+ (unsigned int)wire_offset,
+ (long)offset));
+ return offset;
+ }
+ return END_OF_DIRECTORY_OFFSET;
+}
+
/****************************************************************************
Fetch the dir ptr and seek it given the 5 byte server field.
****************************************************************************/
{
unsigned int key = *(unsigned char *)buf;
struct dptr_struct *dptr = dptr_get(sconn, key, false);
- uint32 offset;
+ uint32_t wire_offset;
long seekoff;
if (!dptr) {
return(NULL);
}
*num = key;
- offset = IVAL(buf,1);
- if (offset == (uint32)-1) {
- seekoff = END_OF_DIRECTORY_OFFSET;
- } else {
- seekoff = (long)offset;
- }
+ wire_offset = IVAL(buf,1);
+ seekoff = map_wire_to_dir_offset(dptr, wire_offset);
SeekDir(dptr->dir_hnd,seekoff);
DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
key, dptr->path, (int)seekoff));
return(dptr);
}
-/****************************************************************************
- Check that a file matches a particular file type.
-****************************************************************************/
-
-bool dir_check_ftype(uint32_t mode, uint32_t dirtype)
-{
- uint32_t mask;
-
- /* Check the "may have" search bits. */
- if (((mode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) != 0)
- return False;
-
- /* Check the "must have" bits, which are the may have bits shifted eight */
- /* If must have bit is set, the file/dir can not be returned in search unless the matching
- file attribute is set */
- mask = ((dirtype >> 8) & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)); /* & 0x37 */
- if(mask) {
- if((mask & (mode & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) == mask) /* check if matching attribute present */
- return True;
- else
- return False;
- }
-
- return True;
-}
-
static bool mangle_mask_match(connection_struct *conn,
const char *filename,
const char *mask)
while (true) {
long cur_offset;
long prev_offset;
- SMB_STRUCT_STAT sbuf;
+ SMB_STRUCT_STAT sbuf = { 0 };
char *dname = NULL;
bool isdots;
char *fname = NULL;
bool is_visible_file(connection_struct *conn, const char *dir_path,
const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
{
- bool hide_unreadable = lp_hideunreadable(SNUM(conn));
- bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
+ bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
+ bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
bool hide_special = lp_hide_special_files(SNUM(conn));
char *entry = NULL;
struct smb_filename *smb_fname_base = NULL;