summaryrefslogtreecommitdiffstats
path: root/source/smbd
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2002-06-17 18:36:36 +0000
committerGerald Carter <jerry@samba.org>2002-06-17 18:36:36 +0000
commit1e6e5b299c235b513095a76a4cd9fffc41e8fc9c (patch)
tree9f741529073ad411cc7328334e26d3e35b1d33f1 /source/smbd
parenta11c5d7ad07d259d764aede4745d13f8163a8212 (diff)
downloadsamba-1e6e5b299c235b513095a76a4cd9fffc41e8fc9c.tar.gz
samba-1e6e5b299c235b513095a76a4cd9fffc41e8fc9c.tar.xz
samba-1e6e5b299c235b513095a76a4cd9fffc41e8fc9c.zip
beginning to sync up for 2.2.5 release....
Diffstat (limited to 'source/smbd')
-rw-r--r--source/smbd/chgpasswd.c8
-rw-r--r--source/smbd/dfree.c9
-rw-r--r--source/smbd/dir.c154
-rw-r--r--source/smbd/filename.c786
-rw-r--r--source/smbd/mangle.c1075
-rw-r--r--source/smbd/mangle_hash.c935
-rw-r--r--source/smbd/mangle_hash2.c24
-rw-r--r--source/smbd/mangle_map.c2
-rw-r--r--source/smbd/notify_kernel.c98
-rw-r--r--source/smbd/nttrans.c11
-rw-r--r--source/smbd/open.c4
-rw-r--r--source/smbd/oplock.c75
-rw-r--r--source/smbd/oplock_irix.c18
-rw-r--r--source/smbd/oplock_linux.c57
-rw-r--r--source/smbd/posix_acls.c170
-rw-r--r--source/smbd/process.c49
-rw-r--r--source/smbd/quotas.c104
-rw-r--r--source/smbd/reply.c25
-rw-r--r--source/smbd/server.c6
-rw-r--r--source/smbd/service.c4
-rw-r--r--source/smbd/trans2.c84
-rw-r--r--source/smbd/uid.c4
-rw-r--r--source/smbd/vfs-wrap.c5
23 files changed, 1507 insertions, 2200 deletions
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index bc91d776936..33ecfc5c2ff 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -193,16 +193,16 @@ static int dochild(int master, char *slavedev, char *name,
}
stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
stermios.c_lflag |= ICANON;
+#ifdef ONLCR
stermios.c_oflag &= ~(ONLCR);
- if (tcsetattr(0, TCSANOW, &stermios) < 0)
- {
+#endif
+ if (tcsetattr(0, TCSANOW, &stermios) < 0) {
DEBUG(3, ("could not set attributes of pty\n"));
return (False);
}
/* make us completely into the right uid */
- if (!as_root)
- {
+ if (!as_root) {
become_user_permanently(uid, gid);
}
diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c
index abc3637056d..e55e40c030d 100644
--- a/source/smbd/dfree.c
+++ b/source/smbd/dfree.c
@@ -22,8 +22,9 @@
#include "includes.h"
/****************************************************************************
-normalise for DOS usage
+ Normalise for DOS usage.
****************************************************************************/
+
static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
{
/* check if the disk is beyond the max disk size */
@@ -60,7 +61,7 @@ static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,
/****************************************************************************
- return number of 1K blocks available on a path and total number
+ Return number of 1K blocks available on a path and total number.
****************************************************************************/
static SMB_BIG_UINT disk_free(char *path, BOOL small_query,
@@ -154,10 +155,10 @@ static SMB_BIG_UINT disk_free(char *path, BOOL small_query,
return(dfree_retval);
}
-
/****************************************************************************
-wrap it to get filenames right
+ Wrap it to get filenames right.
****************************************************************************/
+
SMB_BIG_UINT sys_disk_free(const char *path, BOOL small_query,
SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
{
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index 12e0758596f..cce62870715 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -559,6 +559,12 @@ BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int di
return True;
}
+static BOOL mangle_mask_match(connection_struct *conn, char *filename, char *mask)
+{
+ mangle_map(filename,True,False,SNUM(conn));
+ return mask_match(filename,mask,False);
+}
+
/****************************************************************************
Get an 8.3 directory entry.
****************************************************************************/
@@ -604,14 +610,13 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
*/
if ((strcmp(mask,"*.*") == 0) ||
mask_match(filename,mask,False) ||
- (name_map_mangle(filename,True,False,SNUM(conn)) &&
- mask_match(filename,mask,False)))
+ mangle_mask_match(conn,filename,mask))
{
if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
continue;
- if (!is_8_3(filename, False)) {
- name_map_mangle(filename,True,False,SNUM(conn));
+ if (!mangle_is_8_3(filename, False)) {
+ mangle_map(filename,True,False,SNUM(conn));
}
pstrcpy(fname,filename);
@@ -723,76 +728,83 @@ static BOOL user_can_read_file(connection_struct *conn, char *name)
void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
{
- Dir *dirp;
- char *n;
- DIR *p = conn->vfs_ops.opendir(conn,dos_to_unix_static(name));
- int used=0;
-
- if (!p) return(NULL);
- dirp = (Dir *)malloc(sizeof(Dir));
- if (!dirp) {
- DEBUG(0,("Out of memory in OpenDir\n"));
- conn->vfs_ops.closedir(conn,p);
- return(NULL);
- }
- dirp->pos = dirp->numentries = dirp->mallocsize = 0;
- dirp->data = dirp->current = NULL;
-
- while (True)
- {
- int l;
-
- if (used == 0) {
- n = ".";
- } else if (used == 2) {
- n = "..";
- } else {
- n = vfs_readdirname(conn, p);
- if (n == NULL)
- break;
- if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
- continue;
- }
-
- l = strlen(n)+1;
-
- /* Return value of vfs_readdirname has already gone through
- unix_to_dos() */
-
- /* If it's a vetoed file, pretend it doesn't even exist */
- if (use_veto && conn && IS_VETO_PATH(conn, n)) continue;
+ Dir *dirp;
+ char *n;
+ DIR *p = conn->vfs_ops.opendir(conn,dos_to_unix_static(name));
+ int used=0;
+
+ if (!p)
+ return(NULL);
+ dirp = (Dir *)malloc(sizeof(Dir));
+ if (!dirp) {
+ DEBUG(0,("Out of memory in OpenDir\n"));
+ conn->vfs_ops.closedir(conn,p);
+ return(NULL);
+ }
- /* Honour _hide unreadable_ option */
- if (conn && lp_hideunreadable(SNUM(conn))) {
- char *entry;
- int ret=0;
+ dirp->pos = dirp->numentries = dirp->mallocsize = 0;
+ dirp->data = dirp->current = NULL;
+
+ while (True) {
+ int l;
+ BOOL normal_entry = True;
+
+ 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;
+ }
+
+ l = strlen(n)+1;
+
+ /* Return value of vfs_readdirname has already gone through
+ unix_to_dos() */
+
+ /* If it's a vetoed file, pretend it doesn't even exist */
+ if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
+ continue;
+
+ /* Honour _hide unreadable_ option */
+ if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
+ char *entry;
+ int ret=0;
- if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
- ret = user_can_read_file(conn, entry);
- SAFE_FREE(entry);
- }
- if (!ret) continue;
- }
-
- if (used + l > dirp->mallocsize) {
- int s = MAX(used+l,used+2000);
- char *r;
- r = (char *)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;
- }
- pstrcpy(dirp->data+used,n);
- used += l;
- dirp->numentries++;
- }
+ if (asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
+ ret = user_can_read_file(conn, entry);
+ SAFE_FREE(entry);
+ }
+ if (!ret)
+ continue;
+ }
+
+ if (used + l > dirp->mallocsize) {
+ int s = MAX(used+l,used+2000);
+ char *r;
+ r = (char *)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;
+ }
+ pstrcpy(dirp->data+used,n);
+ used += l;
+ dirp->numentries++;
+ }
- conn->vfs_ops.closedir(conn,p);
- return((void *)dirp);
+ conn->vfs_ops.closedir(conn,p);
+ return((void *)dirp);
}
diff --git a/source/smbd/filename.c b/source/smbd/filename.c
index 90c3db1f9c7..51246dbc056 100644
--- a/source/smbd/filename.c
+++ b/source/smbd/filename.c
@@ -39,59 +39,29 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d
Check if two filenames are equal.
This needs to be careful about whether we are case sensitive.
****************************************************************************/
+
static BOOL fname_equal(char *name1, char *name2)
{
- int l1 = strlen(name1);
- int l2 = strlen(name2);
-
- /* handle filenames ending in a single dot */
- if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot())
- {
- BOOL ret;
- name1[l1-1] = 0;
- ret = fname_equal(name1,name2);
- name1[l1-1] = '.';
- return(ret);
- }
-
- if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot())
- {
- BOOL ret;
- name2[l2-1] = 0;
- ret = fname_equal(name1,name2);
- name2[l2-1] = '.';
- return(ret);
- }
-
- /* now normal filename handling */
- if (case_sensitive)
- return(strcmp(name1,name2) == 0);
-
- return(strequal(name1,name2));
-}
+ /* Normal filename handling */
+ if (case_sensitive)
+ return(strcmp(name1,name2) == 0);
+ return(strequal(name1,name2));
+}
/****************************************************************************
Mangle the 2nd name and check if it is then equal to the first name.
****************************************************************************/
-static BOOL mangled_equal(char *name1, char *name2, int snum)
-{
- pstring tmpname;
-
- if (is_8_3(name2, True))
- return(False);
- pstrcpy(tmpname,name2);
-#if 1
- mangle_name_83(tmpname);
-#else
- name_map_mangle(tmpname,True,False,snum);
-#endif
+static BOOL mangled_equal(char *name1, const char *name2, int snum)
+{
+ pstring tmpname;
- return(strequal(name1,tmpname));
+ pstrcpy(tmpname,name2);
+ mangle_map(tmpname,True,False,snum);
+ return strequal(name1,tmpname);
}
-
/****************************************************************************
This routine is called to convert names from the dos namespace to unix
namespace. It needs to handle any case conversions, mangling, format
@@ -122,413 +92,395 @@ for nlinks = 0, which can never be true for any file).
BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
BOOL *bad_path, SMB_STRUCT_STAT *pst)
{
- SMB_STRUCT_STAT st;
- char *start, *end;
- pstring dirpath;
- pstring orig_path;
- BOOL component_was_mangled = False;
- BOOL name_has_wildcard = False;
+ SMB_STRUCT_STAT st;
+ char *start, *end;
+ pstring dirpath;
+ pstring orig_path;
+ BOOL component_was_mangled = False;
+ BOOL name_has_wildcard = False;
#if 0
- /* Andrew's conservative code... JRA. */
- extern char magic_char;
+ /* Andrew's conservative code... JRA. */
+ extern char magic_char;
#endif
- ZERO_STRUCTP(pst);
-
- *dirpath = 0;
- *bad_path = False;
- if(saved_last_component)
- *saved_last_component = 0;
-
- if (conn->printer) {
- /* we don't ever use the filenames on a printer share as a
- filename - so don't convert them */
- return True;
- }
-
- DEBUG(5, ("unix_convert called on file \"%s\"\n", name));
-
- /*
- * Convert to basic unix format - removing \ chars and cleaning it up.
- */
-
- unix_format(name);
- unix_clean_name(name);
-
- /*
- * Names must be relative to the root of the service - trim any leading /.
- * also trim trailing /'s.
- */
-
- trim_string(name,"/","/");
-
- /*
- * If we trimmed down to a single '\0' character
- * then we should use the "." directory to avoid
- * searching the cache, but not if we are in a
- * printing share.
- */
-
- if (!*name) {
- name[0] = '.';
- name[1] = '\0';
- }
-
- /*
- * Ensure saved_last_component is valid even if file exists.
- */
-
- if(saved_last_component) {
- end = strrchr(name, '/');
- if(end)
- pstrcpy(saved_last_component, end + 1);
- else
- pstrcpy(saved_last_component, name);
- }
-
- if (!case_sensitive &&
- (!case_preserve || (is_8_3(name, False) && !short_case_preserve)))
- strnorm(name);
+ ZERO_STRUCTP(pst);
- /*
- * If we trimmed down to a single '\0' character
- * then we will be using the "." directory.
- * As we know this is valid we can return true here.
- */
+ *dirpath = 0;
+ *bad_path = False;
+ if(saved_last_component)
+ *saved_last_component = 0;
- if(!*name)
- return(True);
+ if (conn->printer) {
+ /* we don't ever use the filenames on a printer share as a
+ filename - so don't convert them */
+ return True;
+ }
- start = name;
- while (strncmp(start,"./",2) == 0)
- start += 2;
-
- pstrcpy(orig_path, name);
-
- if(stat_cache_lookup(conn, name, dirpath, &start, &st)) {
- *pst = st;
- return True;
- }
-
- /*
- * stat the name - if it exists then we are all done!
- */
-
- if (vfs_stat(conn,name,&st) == 0) {
- stat_cache_add(orig_path, name);
- DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
- *pst = st;
- return(True);
- }
-
- DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
- name, dirpath, start));
-
- /*
- * A special case - if we don't have any mangling chars and are case
- * sensitive then searching won't help.
- */
-
- if (case_sensitive && !is_mangled(name) &&
- !lp_strip_dot() && !use_mangled_map)
- return(False);
-
- name_has_wildcard = ms_has_wild(start);
-
- /*
- * is_mangled() was changed to look at an entire pathname, not
- * just a component. JRA.
- */
-
- if(is_mangled(start))
- component_was_mangled = True;
-
-#if 0
- /* Keep Andrew's conservative code around, just in case. JRA. */
- /* this is an extremely conservative test for mangled names. */
- if (strchr(start,magic_char))
- component_was_mangled = True;
-#endif
-
- /*
- * Now we need to recursively match the name against the real
- * directory structure.
- */
-
- /*
- * Match each part of the path name separately, trying the names
- * as is first, then trying to scan the directory for matching names.
- */
-
- for (; start ; start = (end?end+1:(char *)NULL)) {
- /*
- * Pinpoint the end of this section of the filename.
- */
- end = strchr(start, '/');
-
- /*
- * Chop the name at this point.
- */
- if (end)
- *end = 0;
-
- if(saved_last_component != 0)
- pstrcpy(saved_last_component, end ? end + 1 : start);
-
- /*
- * Check if the name exists up to this point.
- */
-
- if (vfs_stat(conn,name, &st) == 0) {
- /*
- * It exists. it must either be a directory or this must be
- * the last part of the path for it to be OK.
- */
- if (end && !(st.st_mode & S_IFDIR)) {
- /*
- * An intermediate part of the name isn't a directory.
- */
- DEBUG(5,("Not a dir %s\n",start));
- *end = '/';
- return(False);
- }
-
- } else {
- pstring rest;
-
- /* Stat failed - ensure we don't use it. */
- ZERO_STRUCT(st);
- *rest = 0;
-
- /*
- * Remember the rest of the pathname so it can be restored
- * later.
- */
-
- if (end)
- pstrcpy(rest,end+1);
-
- /*
- * Try to find this part of the path in the directory.
- */
-
- if (ms_has_wild(start) || !scan_directory(dirpath, start, conn, end?True:False)) {
- if (end) {
- /*
- * An intermediate part of the name can't be found.
- */
- DEBUG(5,("Intermediate not found %s\n",start));
- *end = '/';
-
- /*
- * We need to return the fact that the intermediate
- * name resolution failed. This is used to return an
- * error of ERRbadpath rather than ERRbadfile. Some
- * Windows applications depend on the difference between
- * these two errors.
- */
- *bad_path = True;
- return(False);
- }
+ DEBUG(5, ("unix_convert called on file \"%s\"\n", name));
+
+ /*
+ * Convert to basic unix format - removing \ chars and cleaning it up.
+ */
+
+ unix_format(name);
+ unix_clean_name(name);
+
+ /*
+ * Names must be relative to the root of the service - trim any leading /.
+ * also trim trailing /'s.
+ */
+
+ trim_string(name,"/","/");
+
+ /*
+ * If we trimmed down to a single '\0' character
+ * then we should use the "." directory to avoid
+ * searching the cache, but not if we are in a
+ * printing share.
+ */
+
+ if (!*name) {
+ name[0] = '.';
+ name[1] = '\0';
+ }
+
+ /*
+ * Ensure saved_last_component is valid even if file exists.
+ */
+
+ if(saved_last_component) {
+ end = strrchr(name, '/');
+ if(end)
+ pstrcpy(saved_last_component, end + 1);
+ else
+ pstrcpy(saved_last_component, name);
+ }
+
+ if (!case_sensitive && (!case_preserve || (mangle_is_8_3(name, False) && !short_case_preserve)))
+ strnorm(name);
+
+ /*
+ * If we trimmed down to a single '\0' character
+ * then we will be using the "." directory.
+ * As we know this is valid we can return true here.
+ */
+
+ if(!*name)
+ return(True);
+
+ start = name;
+ while (strncmp(start,"./",2) == 0)
+ start += 2;
+
+ pstrcpy(orig_path, name);
+
+ if(stat_cache_lookup(conn, name, dirpath, &start, &st)) {
+ *pst = st;
+ return True;
+ }
+
+ /*
+ * stat the name - if it exists then we are all done!
+ */
+
+ if (vfs_stat(conn,name,&st) == 0) {
+ stat_cache_add(orig_path, name);
+ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+ *pst = st;
+ return(True);
+ }
+
+ DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start));
+
+ /*
+ * A special case - if we don't have any mangling chars and are case
+ * sensitive then searching won't help.
+ */
+
+ if (case_sensitive && !mangle_is_mangled(name) && !use_mangled_map)
+ return(False);
+
+ name_has_wildcard = ms_has_wild(start);
+
+ /*
+ * is_mangled() was changed to look at an entire pathname, not
+ * just a component. JRA.
+ */
+
+ if(mangle_is_mangled(start))
+ component_was_mangled = True;
+
+ /*
+ * Now we need to recursively match the name against the real
+ * directory structure.
+ */
+
+ /*
+ * Match each part of the path name separately, trying the names
+ * as is first, then trying to scan the directory for matching names.
+ */
+
+ for (; start ; start = (end?end+1:(char *)NULL)) {
+ /*
+ * Pinpoint the end of this section of the filename.
+ */
+ end = strchr(start, '/');
+
+ /*
+ * Chop the name at this point.
+ */
+ if (end)
+ *end = 0;
+
+ if(saved_last_component != 0)
+ pstrcpy(saved_last_component, end ? end + 1 : start);
+
+ /*
+ * Check if the name exists up to this point.
+ */
+
+ if (vfs_stat(conn,name, &st) == 0) {
+ /*
+ * It exists. it must either be a directory or this must be
+ * the last part of the path for it to be OK.
+ */
+ if (end && !(st.st_mode & S_IFDIR)) {
+ /*
+ * An intermediate part of the name isn't a directory.
+ */
+ DEBUG(5,("Not a dir %s\n",start));
+ *end = '/';
+ return(False);
+ }
+
+ } else {
+ pstring rest;
+
+ /* Stat failed - ensure we don't use it. */
+ ZERO_STRUCT(st);
+ *rest = 0;
+
+ /*
+ * Remember the rest of the pathname so it can be restored
+ * later.
+ */
+
+ if (end)
+ pstrcpy(rest,end+1);
+
+ /*
+ * Try to find this part of the path in the directory.
+ */
+
+ if (ms_has_wild(start) || !scan_directory(dirpath, start, conn, end?True:False)) {
+ if (end) {
+ /*
+ * An intermediate part of the name can't be found.
+ */
+ DEBUG(5,("Intermediate not found %s\n",start));
+ *end = '/';
+
+ /*
+ * We need to return the fact that the intermediate
+ * name resolution failed. This is used to return an
+ * error of ERRbadpath rather than ERRbadfile. Some
+ * Windows applications depend on the difference between
+ * these two errors.
+ */
+ *bad_path = True;
+ return(False);
+ }
- /*
- * Just the last part of the name doesn't exist.
- * We may need to strupper() or strlower() it in case
- * this conversion is being used for file creation
- * purposes. If the filename is of mixed case then
- * don't normalise it.
- */
-
- if (!case_preserve && (!strhasupper(start) || !strhaslower(start)))
- strnorm(start);
-
- /*
- * check on the mangled stack to see if we can recover the
- * base of the filename.
- */
-
- if (is_mangled(start)) {
- check_mangled_cache( start );
- }
-
- DEBUG(5,("New file %s\n",start));
- return(True);
- }
-
- /*
- * Restore the rest of the string. If the string was mangled the size
- * may have changed.
- */
- if (end) {
- end = start + strlen(start);
- pstrcat(start,"/");
- pstrcat(start,rest);
- *end = '\0';
- }
- } /* end else */
-
- /*
- * Add to the dirpath that we have resolved so far.
- */
- if (*dirpath)
- pstrcat(dirpath,"/");
-
- pstrcat(dirpath,start);
-
- /*
- * Don't cache a name with mangled or wildcard components
- * as this can change the size.
- */
-
- if(!component_was_mangled && !name_has_wildcard)
- stat_cache_add(orig_path, dirpath);
-
- /*
- * Restore the / that we wiped out earlier.
- */
- if (end)
- *end = '/';
- }
+ /*
+ * Just the last part of the name doesn't exist.
+ * We may need to strupper() or strlower() it in case
+ * this conversion is being used for file creation
+ * purposes. If the filename is of mixed case then
+ * don't normalise it.
+ */
+
+ if (!case_preserve && (!strhasupper(start) || !strhaslower(start)))
+ strnorm(start);
+
+ /*
+ * check on the mangled stack to see if we can recover the
+ * base of the filename.
+ */
+
+ if (mangle_is_mangled(start)) {
+ mangle_check_cache( start );
+ }
+
+ DEBUG(5,("New file %s\n",start));
+ return(True);
+ }
+
+ /*
+ * Restore the rest of the string. If the string was mangled the size
+ * may have changed.
+ */
+ if (end) {
+ end = start + strlen(start);
+ pstrcat(start,"/");
+ pstrcat(start,rest);
+ *end = '\0';
+ }
+ } /* end else */
+
+ /*
+ * Add to the dirpath that we have resolved so far.
+ */
+ if (*dirpath)
+ pstrcat(dirpath,"/");
+
+ pstrcat(dirpath,start);
+
+ /*
+ * Don't cache a name with mangled or wildcard components
+ * as this can change the size.
+ */
+
+ if(!component_was_mangled && !name_has_wildcard)
+ stat_cache_add(orig_path, dirpath);
+
+ /*
+ * Restore the / that we wiped out earlier.
+ */
+ if (end)
+ *end = '/';
+ }
- /*
- * Don't cache a name with mangled or wildcard components
- * as this can change the size.
- */
+ /*
+ * Don't cache a name with mangled or wildcard components
+ * as this can change the size.
+ */
- if(!component_was_mangled && !name_has_wildcard)
- stat_cache_add(orig_path, name);
+ if(!component_was_mangled && !name_has_wildcard)
+ stat_cache_add(orig_path, name);
- /*
- * If we ended up resolving the entire path then return a valid
- * stat struct if we got one.
- */
+ /*
+ * If we ended up resolving the entire path then return a valid
+ * stat struct if we got one.
+ */
- if (VALID_STAT(st) && (strlen(orig_path) == strlen(name)))
- *pst = st;
+ if (VALID_STAT(st) && (strlen(orig_path) == strlen(name)))
+ *pst = st;
- /*
- * The name has been resolved.
- */
+ /*
+ * The name has been resolved.
+ */
- DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
- return(True);
+ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+ return(True);
}
-
/****************************************************************************
-check a filename - possibly caling reducename
-
-This is called by every routine before it allows an operation on a filename.
-It does any final confirmation necessary to ensure that the filename is
-a valid one for the user to access.
+ Check a filename - possibly caling reducename.
+ This is called by every routine before it allows an operation on a filename.
+ It does any final confirmation necessary to ensure that the filename is
+ a valid one for the user to access.
****************************************************************************/
+
BOOL check_name(char *name,connection_struct *conn)
{
- BOOL ret;
+ BOOL ret;
- errno = 0;
+ errno = 0;
- if (IS_VETO_PATH(conn, name)) {
- DEBUG(5,("file path name %s vetoed\n",name));
- return(0);
- }
+ if(IS_VETO_PATH(conn, name)) {
+ if(strcmp(name, ".") && strcmp(name, "..")) {
+ DEBUG(5,("file path name %s vetoed\n",name));
+ return(0);
+ }
+ }
- ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn)));
+ ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn)));
- /* Check if we are allowing users to follow symlinks */
- /* Patch from David Clerc <David.Clerc@cui.unige.ch>
- University of Geneva */
+ /* Check if we are allowing users to follow symlinks */
+ /* Patch from David Clerc <David.Clerc@cui.unige.ch>
+ University of Geneva */
#ifdef S_ISLNK
- if (!lp_symlinks(SNUM(conn))) {
- SMB_STRUCT_STAT statbuf;
- if ( (conn->vfs_ops.lstat(conn,dos_to_unix_static(name),&statbuf) != -1) &&
- (S_ISLNK(statbuf.st_mode)) ) {
- DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
- ret=0;
- }
- }
+ if (!lp_symlinks(SNUM(conn))) {
+ SMB_STRUCT_STAT statbuf;
+ if ( (conn->vfs_ops.lstat(conn,dos_to_unix_static(name),&statbuf) != -1) &&
+ (S_ISLNK(statbuf.st_mode)) ) {
+ DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
+ ret=0;
+ }
+ }
#endif
- if (!ret)
- DEBUG(5,("check_name on %s failed\n",name));
+ if (!ret)
+ DEBUG(5,("check_name on %s failed\n",name));
- return(ret);
+ return(ret);
}
-
/****************************************************************************
-scan a directory to find a filename, matching without case sensitivity
-
-If the name looks like a mangled name then try via the mangling functions
+ Scan a directory to find a filename, matching without case sensitivity.
+ If the name looks like a mangled name then try via the mangling functions
****************************************************************************/
+
static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache)
{
- void *cur_dir;
- char *dname;
- BOOL mangled;
- pstring name2;
-
- mangled = is_mangled(name);
-
- /* handle null paths */
- if (*path == 0)
- path = ".";
-
- if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) {
- pstrcpy(name, dname);
- return(True);
- }
-
- /*
- * The incoming name can be mangled, and if we de-mangle it
- * here it will not compare correctly against the filename (name2)
- * read from the directory and then mangled by the name_map_mangle()
- * call. We need to mangle both names or neither.
- * (JRA).
- */
- if (mangled)
- mangled = !check_mangled_cache( name );
-
- /* open the directory */
- if (!(cur_dir = OpenDir(conn, path, True))) {
- DEBUG(3,("scan dir didn't open dir [%s]\n",path));
- return(False);
- }
-
- /* now scan for matching names */
- while ((dname = ReadDirName(cur_dir))) {
- if (*dname == '.' && (strequal(dname,".") || strequal(dname,"..")))
- continue;
-
- /*
- * dname here is the unmangled name.
- */
- pstrcpy(name2,dname);
- if (!name_map_mangle(name2,False,True,SNUM(conn)))
- continue;
-
- /*
- * At this point name2 is the mangled name, dname is the unmangled name.
- * name is either mangled or not, depending on the state of the "mangled"
- * variable. JRA.
- */
-
- /*
- * Check mangled name against mangled name, or unmangled name
- * against unmangled name.
- */
-
- if ((mangled && mangled_equal(name,name2,SNUM(conn))) || fname_equal(name, dname)) {
- /* we've found the file, change it's name and return */
- if (docache)
- DirCacheAdd(path,name,dname,SNUM(conn));
- pstrcpy(name, dname);
- CloseDir(cur_dir);
- return(True);
- }
- }
-
- CloseDir(cur_dir);
- return(False);
+ void *cur_dir;
+ char *dname;
+ BOOL mangled;
+
+ mangled = mangle_is_mangled(name);
+
+ /* handle null paths */
+ if (*path == 0)
+ path = ".";
+
+ if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) {
+ pstrcpy(name, dname);
+ return(True);
+ }
+
+ /*
+ * The incoming name can be mangled, and if we de-mangle it
+ * here it will not compare correctly against the filename (name2)
+ * read from the directory and then mangled by the name_map_mangle()
+ * call. We need to mangle both names or neither.
+ * (JRA).
+ */
+ if (mangled)
+ mangled = !mangle_check_cache( name );
+
+ /* open the directory */
+ if (!(cur_dir = OpenDir(conn, path, True))) {
+ DEBUG(3,("scan dir didn't open dir [%s]\n",path));
+ return(False);
+ }
+
+ /* now scan for matching names */
+ while ((dname = ReadDirName(cur_dir))) {
+ if (*dname == '.' && (strequal(dname,".") || strequal(dname,"..")))
+ continue;
+
+ /*
+ * At this point dname is the unmangled name.
+ * name is either mangled or not, depending on the state of the "mangled"
+ * variable. JRA.
+ */
+
+ /*
+ * Check mangled name against mangled name, or unmangled name
+ * against unmangled name.
+ */
+
+ if ((mangled && mangled_equal(name,dname,SNUM(conn))) || fname_equal(name, dname)) {
+ /* we've found the file, change it's name and return */
+ if (docache)
+ DirCacheAdd(path,name,dname,SNUM(conn));
+ pstrcpy(name, dname);
+ CloseDir(cur_dir);
+ return(True);
+ }
+ }
+
+ CloseDir(cur_dir);
+ return(False);
}
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index ee1f24931a5..4b8132a7ebe 100644
--- a/source/smbd/mangle.c
+++ b/source/smbd/mangle.c
@@ -1,8 +1,7 @@
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Name mangling
- Copyright (C) Andrew Tridgell 1992-1998
+ Unix SMB/CIFS implementation.
+ Name mangling interface
+ Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,1014 +18,106 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* -------------------------------------------------------------------------- **
- * Notable problems...
- *
- * March/April 1998 CRH
- * - Many of the functions in this module overwrite string buffers passed to
- * them. This causes a variety of problems and is, generally speaking,
- * dangerous and scarry. See the kludge notes in name_map_mangle()
- * below.
- * - It seems that something is calling name_map_mangle() twice. The
- * first call is probably some sort of test. Names which contain
- * illegal characters are being doubly mangled. I'm not sure, but
- * I'm guessing the problem is in server.c.
- *
- * -------------------------------------------------------------------------- **
- */
-
-/* -------------------------------------------------------------------------- **
- * History...
- *
- * March/April 1998 CRH
- * Updated a bit. Rewrote is_mangled() to be a bit more selective.
- * Rewrote the mangled name cache. Added comments here and there.
- * &c.
- * -------------------------------------------------------------------------- **
- */
-
#include "includes.h"
+static struct mangle_fns *mangle_fns;
-/* -------------------------------------------------------------------------- **
- * External Variables...
- */
-
-extern int case_default; /* Are conforming 8.3 names all upper or lower? */
-extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */
-
-/* -------------------------------------------------------------------------- **
- * Other stuff...
- *
- * magic_char - This is the magic char used for mangling. It's
- * global. There is a call to lp_magicchar() in server.c
- * that is used to override the initial value.
- *
- * MANGLE_BASE - This is the number of characters we use for name mangling.
- *
- * basechars - The set characters used for name mangling. This
- * is static (scope is this file only).
- *
- * mangle() - Macro used to select a character from basechars (i.e.,
- * mangle(n) will return the nth digit, modulo MANGLE_BASE).
- *
- * chartest - array 0..255. The index range is the set of all possible
- * values of a byte. For each byte value, the content is a
- * two nibble pair. See BASECHAR_MASK and ILLEGAL_MASK,
- * below.
- *
- * ct_initialized - False until the chartest array has been initialized via
- * a call to init_chartest().
- *
- * BASECHAR_MASK - Masks the upper nibble of a one-byte value.
- *
- * ILLEGAL_MASK - Masks the lower nibble of a one-byte value.
- *
- * isbasecahr() - Given a character, check the chartest array to see
- * if that character is in the basechars set. This is
- * faster than using strchr().
- *
- * isillegal() - Given a character, check the chartest array to see
- * if that character is in the illegal characters set.
- * This is faster than using strchr().
- *
- * mangled_cache - Cache header used for storing mangled -> original
- * reverse maps.
- *
- * mc_initialized - False until the mangled_cache structure has been
- * initialized via a call to reset_mangled_cache().
- *
- * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the
- * cache. A value of 0 indicates "infinite".
- *
- * MANGLED_CACHE_MAX_MEMORY - Default maximum amount of memory for the
- * cache. When the cache was kept as an array of 256
- * byte strings, the default cache size was 50 entries.
- * This required a fixed 12.5Kbytes of memory. The
- * mangled stack parameter is no longer used (though
- * this might change). We're now using a fixed 16Kbyte
- * maximum cache size. This will probably be much more
- * than 50 entries.
- */
-
-char magic_char = '~';
-
-static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
-#define MANGLE_BASE (sizeof(basechars)/sizeof(char)-1)
-
-static unsigned char chartest[256] = { 0 };
-static BOOL ct_initialized = False;
-
-#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
-#define BASECHAR_MASK 0xf0
-#define ILLEGAL_MASK 0x0f
-#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
-#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
-
-static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } };
-static BOOL mc_initialized = False;
-#define MANGLED_CACHE_MAX_ENTRIES 1024
-#define MANGLED_CACHE_MAX_MEMORY 0
-
-
-/* -------------------------------------------------------------------------- **
- * Functions...
- */
-
-/* ************************************************************************** **
- * Initialize the static character test array.
- *
- * Input: none
- *
- * Output: none
- *
- * Notes: This function changes (loads) the contents of the <chartest>
- * array. The scope of <chartest> is this file.
- *
- * ************************************************************************** **
- */
-static void init_chartest( void )
- {
- char *illegalchars = "*\\/?<>|\":";
- unsigned char *s;
-
- memset( (char *)chartest, '\0', 256 );
-
- for( s = (unsigned char *)illegalchars; *s; s++ )
- chartest[*s] = ILLEGAL_MASK;
-
- for( s = (unsigned char *)basechars; *s; s++ )
- chartest[*s] |= BASECHAR_MASK;
-
- ct_initialized = True;
- } /* init_chartest */
-
-/* ************************************************************************** **
- * Return True if a name is a special msdos reserved name.
- *
- * Input: fname - String containing the name to be tested.
- *
- * Output: True, if the name matches one of the list of reserved names.
- *
- * Notes: This is a static function called by is_8_3(), below.
- *
- * ************************************************************************** **
- */
-static BOOL is_reserved_msdos( char *fname )
- {
- char upperFname[13];
- char *p;
-
- StrnCpy (upperFname, fname, 12);
-
- /* lpt1.txt and con.txt etc are also illegal */
- p = strchr(upperFname,'.');
- if( p )
- *p = '\0';
-
- strupper( upperFname );
- p = upperFname + 1;
- switch( upperFname[0] )
- {
- case 'A':
- if( 0 == strcmp( p, "UX" ) )
- return( True );
- break;
- case 'C':
- if( (0 == strcmp( p, "LOCK$" ))
- || (0 == strcmp( p, "ON" ))
- || (0 == strcmp( p, "OM1" ))
- || (0 == strcmp( p, "OM2" ))
- || (0 == strcmp( p, "OM3" ))
- || (0 == strcmp( p, "OM4" ))
- )
- return( True );
- break;
- case 'L':
- if( (0 == strcmp( p, "PT1" ))
- || (0 == strcmp( p, "PT2" ))
- || (0 == strcmp( p, "PT3" ))
- )
- return( True );
- break;
- case 'N':
- if( 0 == strcmp( p, "UL" ) )
- return( True );
- break;
- case 'P':
- if( 0 == strcmp( p, "RN" ) )
- return( True );
- break;
- }
-
- return( False );
- } /* is_reserved_msdos */
-
-/* ************************************************************************** **
- * Determine whether or not a given name contains illegal characters, even
- * long names.
- *
- * Input: name - The name to be tested.
- *
- * Output: True if an illegal character was found in <name>, else False.
- *
- * Notes: This is used to test a name on the host system, long or short,
- * for characters that would be illegal on most client systems,
- * particularly DOS and Windows systems. Unix and AmigaOS, for
- * example, allow a filenames which contain such oddities as
- * quotes ("). If a name is found which does contain an illegal
- * character, it is mangled even if it conforms to the 8.3
- * format.
- *
- * ************************************************************************** **
- */
-static BOOL is_illegal_name( char *name )
- {
- unsigned char *s;
- int skip;
-
- if( !name )
- return( True );
-
- if( !ct_initialized )
- init_chartest();
-
- s = (unsigned char *)name;
- while( *s )
- {
- skip = get_character_len( *s );
- if( skip != 0 )
- {
- s += skip;
- }
- else
- {
- if( isillegal( *s ) )
- return( True );
- else
- s++;
- }
- }
+/* this allows us to add more mangling backends */
+static struct {
+ char *name;
+ struct mangle_fns *(*init_fn)(void);
+} mangle_backends[] = {
+ { "hash", mangle_hash_init },
+ { "hash2", mangle_hash2_init },
+ { NULL, NULL }
+};
- return( False );
- } /* is_illegal_name */
-
-/* ************************************************************************** **
- * Return True if the name *could be* a mangled name.
- *
- * Input: s - A path name - in UNIX pathname format.
- *
- * Output: True if the name matches the pattern described below in the
- * notes, else False.
- *
- * Notes: The input name is *not* tested for 8.3 compliance. This must be
- * done separately. This function returns true if the name contains
- * a magic character followed by excactly two characters from the
- * basechars list (above), which in turn are followed either by the
- * nul (end of string) byte or a dot (extension) or by a '/' (end of
- * a directory name).
- *
- * ************************************************************************** **
- */
-BOOL is_mangled( char *s )
+/*
+ initialise the mangling subsystem
+*/
+static void mangle_init(void)
{
- char *magic;
- BOOL ret = False;
-
- if( !ct_initialized )
- init_chartest();
-
- magic = strchr( s, magic_char );
- while( magic && magic[1] && magic[2] ) {
- /* 3 chars, 1st is magic. */
- if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */
- && isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */
- && isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */
- ret = ( True ); /* If all above, then true, */
- magic = strchr( magic+1, magic_char ); /* else seek next magic. */
- }
-
- DEBUG(10,("is_mangled: %s : %s\n", s, ret ? "True" : "False"));
-
- return ret;
-} /* is_mangled */
-
-/* ************************************************************************** **
- * Return True if the name is a valid DOS name in 8.3 DOS format.
- *
- * Input: fname - File name to be checked.
- * check_case - If True, and if case_mangle is True, then the
- * name will be checked to see if all characters
- * are the correct case. See case_mangle and
- * case_default above.
- *
- * Output: True if the name is a valid DOS name, else False.
- *
- * ************************************************************************** **
- */
-BOOL is_8_3( char *fname, BOOL check_case )
- {
- int len;
- int l;
- int skip;
- char *p;
- char *dot_pos;
- char *slash_pos = strrchr( fname, '/' );
-
- /* If there is a directory path, skip it. */
- if( slash_pos )
- fname = slash_pos + 1;
- len = strlen( fname );
-
- DEBUG( 5, ( "Checking %s for 8.3\n", fname ) );
-
- /* Can't be 0 chars or longer than 12 chars */
- if( (len == 0) || (len > 12) )
- return( False );
-
- /* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
- if( is_reserved_msdos( fname ) )
- return( False );
-
- /* Check that all characters are the correct case, if asked to do so. */
- if( check_case && case_mangle )
- {
- switch( case_default )
- {
- case CASE_LOWER:
- if( strhasupper( fname ) )
- return(False);
- break;
- case CASE_UPPER:
- if( strhaslower( fname ) )
- return(False);
- break;
- }
- }
-
- /* Can't contain invalid dos chars */
- /* Windows use the ANSI charset.
- But filenames are translated in the PC charset.
- This Translation may be more or less relaxed depending
- the Windows application. */
-
- /* %%% A nice improvment to name mangling would be to translate
- filename to ANSI charset on the smb server host */
-
- p = fname;
- dot_pos = NULL;
- while( *p )
- {
- if( (skip = get_character_len( *p )) != 0 )
- p += skip;
- else
- {
- if( *p == '.' && !dot_pos )
- dot_pos = (char *)p;
- else
- if( !isdoschar( *p ) )
- return( False );
- p++;
- }
- }
-
- /* no dot and less than 9 means OK */
- if( !dot_pos )
- return( len <= 8 );
-
- l = PTR_DIFF( dot_pos, fname );
-
- /* base must be at least 1 char except special cases . and .. */
- if( l == 0 )
- return( 0 == strcmp( fname, "." ) || 0 == strcmp( fname, ".." ) );
-
- /* base can't be greater than 8 */
- if( l > 8 )
- return( False );
-
- /* see smb.conf(5) for a description of the 'strip dot' parameter. */
- if( lp_strip_dot()
- && len - l == 1
- && !strchr( dot_pos + 1, '.' ) )
- {
- *dot_pos = 0;
- return( True );
- }
-
- /* extension must be between 1 and 3 */
- if( (len - l < 2 ) || (len - l > 4) )
- return( False );
-
- /* extensions may not have a dot */
- if( strchr( dot_pos+1, '.' ) )
- return( False );
-
- /* must be in 8.3 format */
- return( True );
- } /* is_8_3 */
-
-
-/* ************************************************************************** **
- * Compare two cache keys and return a value indicating their ordinal
- * relationship.
- *
- * Input: ItemPtr - Pointer to a comparison key. In this case, this will
- * be a mangled name string.
- * NodePtr - Pointer to a node in the cache. The node structure
- * will be followed in memory by a mangled name string.
- *
- * Output: A signed integer, as follows:
- * (x < 0) <==> Key1 less than Key2
- * (x == 0) <==> Key1 equals Key2
- * (x > 0) <==> Key1 greater than Key2
- *
- * Notes: This is a ubiqx-style comparison routine. See ubi_BinTree for
- * more info.
- *
- * ************************************************************************** **
- */
-static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
- {
- char *Key1 = (char *)ItemPtr;
- char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
-
- DEBUG(100,("cache_compare: %s %s\n", Key1, Key2));
-
- return( StrCaseCmp( Key1, Key2 ) );
- } /* cache_compare */
-
-/* ************************************************************************** **
- * Free a cache entry.
- *
- * Input: WarrenZevon - Pointer to the entry that is to be returned to
- * Nirvana.
- * Output: none.
- *
- * Notes: This function gets around the possibility that the standard
- * free() function may be implemented as a macro, or other evil
- * subversions (oh, so much fun).
- *
- * ************************************************************************** **
- */
-static void cache_free_entry( ubi_trNodePtr WarrenZevon )
- {
- ZERO_STRUCTP(WarrenZevon);
- SAFE_FREE( WarrenZevon );
- } /* cache_free_entry */
+ int i;
+ char *method;
-/* ************************************************************************** **
- * Initializes or clears the mangled cache.
- *
- * Input: none.
- * Output: none.
- *
- * Notes: There is a section below that is commented out. It shows how
- * one might use lp_ calls to set the maximum memory and entry size
- * of the cache. You might also want to remove the constants used
- * in ubi_cacheInit() and replace them with lp_ calls. If so, then
- * the calls to ubi_cacheSetMax*() would be moved into the else
- * clause. Another option would be to pass in the max_entries and
- * max_memory values as parameters. crh 09-Apr-1998.
- *
- * ************************************************************************** **
- */
-void reset_mangled_cache( void )
- {
- if( !mc_initialized )
- {
- (void)ubi_cacheInit( mangled_cache,
- cache_compare,
- cache_free_entry,
- MANGLED_CACHE_MAX_ENTRIES,
- MANGLED_CACHE_MAX_MEMORY );
- mc_initialized = True;
- }
- else
- {
- (void)ubi_cacheClear( mangled_cache );
- }
-
- /*
- (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() );
- (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() );
- */
- } /* reset_mangled_cache */
-
-
-/* ************************************************************************** **
- * Add a mangled name into the cache.
- *
- * Notes: If the mangled cache has not been initialized, then the
- * function will simply fail. It could initialize the cache,
- * but that's not the way it was done before I changed the
- * cache mechanism, so I'm sticking with the old method.
- *
- * If the extension of the raw name maps directly to the
- * extension of the mangled name, then we'll store both names
- * *without* extensions. That way, we can provide consistent
- * reverse mangling for all names that match. The test here is
- * a bit more careful than the one done in earlier versions of
- * mangle.c:
- *
- * - the extension must exist on the raw name,
- * - it must be all lower case
- * - it must match the mangled extension (to prove that no
- * mangling occurred).
- *
- * crh 07-Apr-1998
- *
- * ************************************************************************** **
- */
-static void cache_mangled_name( char *mangled_name, char *raw_name )
- {
- ubi_cacheEntryPtr new_entry;
- char *s1;
- char *s2;
- size_t mangled_len;
- size_t raw_len;
- size_t i;
-
- /* If the cache isn't initialized, give up. */
- if( !mc_initialized )
- return;
+ if (mangle_fns)
+ return;
- /* Init the string lengths. */
- mangled_len = strlen( mangled_name );
- raw_len = strlen( raw_name );
+ method = lp_mangling_method();
- /* See if the extensions are unmangled. If so, store the entry
- * without the extension, thus creating a "group" reverse map.
- */
- s1 = strrchr( mangled_name, '.' );
- if( s1 && (s2 = strrchr( raw_name, '.' )) )
- {
- i = 1;
- while( s1[i] && (tolower( s1[i] ) == s2[i]) )
- i++;
- if( !s1[i] && !s2[i] )
- {
- mangled_len -= i;
- raw_len -= i;
- }
- }
-
- /* Allocate a new cache entry. If the allocation fails, just return. */
- i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
- new_entry = malloc( i );
- if( !new_entry )
- return;
+ /* find the first mangling method that manages to initialise and
+ matches the "mangling method" parameter */
+ for (i=0; mangle_backends[i].name && !mangle_fns; i++) {
+ if (!method || !*method || strcmp(method, mangle_backends[i].name) == 0) {
+ mangle_fns = mangle_backends[i].init_fn();
+ }
+ }
- /* Fill the new cache entry, and add it to the cache. */
- s1 = (char *)(new_entry + 1);
- s2 = (char *)&(s1[mangled_len + 1]);
- (void)StrnCpy( s1, mangled_name, mangled_len );
- (void)StrnCpy( s2, raw_name, raw_len );
- ubi_cachePut( mangled_cache, i, new_entry, s1 );
- } /* cache_mangled_name */
+ if (!mangle_fns) {
+ DEBUG(0,("Failed to initialise mangling system '%s'\n", method));
+ exit_server("mangling init failed");
+ }
+}
-/* ************************************************************************** **
- * Check for a name on the mangled name stack
- *
- * Input: s - Input *and* output string buffer.
- *
- * Output: True if the name was found in the cache, else False.
- *
- * Notes: If a reverse map is found, the function will overwrite the string
- * space indicated by the input pointer <s>. This is frightening.
- * It should be rewritten to return NULL if the long name was not
- * found, and a pointer to the long name if it was found.
- *
- * ************************************************************************** **
- */
-BOOL check_mangled_cache( char *s )
+/*
+ reset the cache. This is called when smb.conf has been reloaded
+*/
+void mangle_reset_cache(void)
{
- ubi_cacheEntryPtr FoundPtr;
- char *ext_start = NULL;
- char *found_name;
- char *saved_ext = NULL;
-
- /* If the cache isn't initialized, give up. */
- if( !mc_initialized )
- return( False );
-
- FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
-
- /* If we didn't find the name *with* the extension, try without. */
- if( !FoundPtr )
- {
- ext_start = strrchr( s, '.' );
- if( ext_start )
- {
- if((saved_ext = strdup(ext_start)) == NULL)
- return False;
-
- *ext_start = '\0';
- FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
- /*
- * At this point s is the name without the
- * extension. We re-add the extension if saved_ext
- * is not null, before freeing saved_ext.
- */
- }
- }
+ mangle_init();
- /* Okay, if we haven't found it we're done. */
- if( !FoundPtr )
- {
- if(saved_ext)
- {
- /* Replace the saved_ext as it was truncated. */
- (void)pstrcat( s, saved_ext );
- SAFE_FREE(saved_ext);
- }
- return( False );
- }
-
- /* If we *did* find it, we need to copy it into the string buffer. */
- found_name = (char *)(FoundPtr + 1);
- found_name += (strlen( found_name ) + 1);
-
- DEBUG( 3, ("Found %s on mangled stack ", s) );
-
- (void)pstrcpy( s, found_name );
- if( saved_ext )
- {
- /* Replace the saved_ext as it was truncated. */
- (void)pstrcat( s, saved_ext );
- SAFE_FREE(saved_ext);
- }
-
- DEBUG( 3, ("as %s\n", s) );
-
- return( True );
-} /* check_mangled_cache */
-
-
-/* ************************************************************************** **
- * Used only in do_fwd_mangled_map(), below.
- * ************************************************************************** **
- */
-static char *map_filename( char *s, /* This is null terminated */
- char *pattern, /* This isn't. */
- int len ) /* This is the length of pattern. */
- {
- static pstring matching_bit; /* The bit of the string which matches */
- /* a * in pattern if indeed there is a * */
- char *sp; /* Pointer into s. */
- char *pp; /* Pointer into p. */
- char *match_start; /* Where the matching bit starts. */
- pstring pat;
-
- StrnCpy( pat, pattern, len ); /* Get pattern into a proper string! */
- pstrcpy( matching_bit, "" ); /* Match but no star gets this. */
- pp = pat; /* Initialize the pointers. */
- sp = s;
-
- if( strequal(s, ".") || strequal(s, ".."))
- {
- return NULL; /* Do not map '.' and '..' */
- }
-
- if( (len == 1) && (*pattern == '*') )
- {
- return NULL; /* Impossible, too ambiguous for */
- } /* words! */
-
- while( (*sp) /* Not the end of the string. */
- && (*pp) /* Not the end of the pattern. */
- && (*sp == *pp) /* The two match. */
- && (*pp != '*') ) /* No wildcard. */
- {
- sp++; /* Keep looking. */
- pp++;
- }
-
- if( !*sp && !*pp ) /* End of pattern. */
- return( matching_bit ); /* Simple match. Return empty string. */
-
- if( *pp == '*' )
- {
- pp++; /* Always interrested in the chacter */
- /* after the '*' */
- if( !*pp ) /* It is at the end of the pattern. */
- {
- StrnCpy( matching_bit, s, sp-s );
- return( matching_bit );
- }
- else
- {
- /* The next character in pattern must match a character further */
- /* along s than sp so look for that character. */
- match_start = sp;
- while( (*sp) /* Not the end of s. */
- && (*sp != *pp) ) /* Not the same */
- sp++; /* Keep looking. */
- if( !*sp ) /* Got to the end without a match. */
- {
- return( NULL );
- } /* Still hope for a match. */
- else
- {
- /* Now sp should point to a matching character. */
- StrnCpy(matching_bit, match_start, sp-match_start);
- /* Back to needing a stright match again. */
- while( (*sp) /* Not the end of the string. */
- && (*pp) /* Not the end of the pattern. */
- && (*sp == *pp) ) /* The two match. */
- {
- sp++; /* Keep looking. */
- pp++;
- }
- if( !*sp && !*pp ) /* Both at end so it matched */
- return( matching_bit );
- else
- return( NULL );
- }
- }
- }
- return( NULL ); /* No match. */
- } /* map_filename */
+ mangle_fns->reset();
+}
+/*
+ see if a filename has come out of our mangling code
+*/
+BOOL mangle_is_mangled(const char *s)
+{
+ return mangle_fns->is_mangled(s);
+}
-/* ************************************************************************** **
- * MangledMap is a series of name pairs in () separated by spaces.
- * If s matches the first of the pair then the name given is the
- * second of the pair. A * means any number of any character and if
- * present in the second of the pair as well as the first the
- * matching part of the first string takes the place of the * in the
- * second.
- *
- * I wanted this so that we could have RCS files which can be used
- * by UNIX and DOS programs. My mapping string is (RCS rcs) which
- * converts the UNIX RCS file subdirectory to lowercase thus
- * preventing mangling.
- *
- * (I think Andrew wrote the above, but I'm not sure. -- CRH)
- *
- * See 'mangled map' in smb.conf(5).
- *
- * ************************************************************************** **
- */
-static void do_fwd_mangled_map(char *s, char *MangledMap)
- {
- char *start=MangledMap; /* Use this to search for mappings. */
- char *end; /* Used to find the end of strings. */
- char *match_string;
- pstring new_string; /* Make up the result here. */
- char *np; /* Points into new_string. */
+/*
+ see if a filename matches the rules of a 8.3 filename
+*/
+BOOL mangle_is_8_3(const char *fname, BOOL check_case)
+{
+ return mangle_fns->is_8_3(fname, check_case, False);
+}
- DEBUG( 5, ("Mangled Mapping '%s' map '%s'\n", s, MangledMap) );
- while( *start )
- {
- while( (*start) && (*start != '(') )
- start++;
- if( !*start )
- continue; /* Always check for the end. */
- start++; /* Skip the ( */
- end = start; /* Search for the ' ' or a ')' */
- DEBUG( 5, ("Start of first in pair '%s'\n", start) );
- while( (*end) && !((*end == ' ') || (*end == ')')) )
- end++;
- if( !*end )
- {
- start = end;
- continue; /* Always check for the end. */
- }
- DEBUG( 5, ("End of first in pair '%s'\n", end) );
- if( (match_string = map_filename( s, start, end-start )) )
- {
- DEBUG( 5, ("Found a match\n") );
- /* Found a match. */
- start = end + 1; /* Point to start of what it is to become. */
- DEBUG( 5, ("Start of second in pair '%s'\n", start) );
- end = start;
- np = new_string;
- while( (*end) /* Not the end of string. */
- && (*end != ')') /* Not the end of the pattern. */
- && (*end != '*') ) /* Not a wildcard. */
- *np++ = *end++;
- if( !*end )
- {
- start = end;
- continue; /* Always check for the end. */
- }
- if( *end == '*' )
- {
- pstrcpy( np, match_string );
- np += strlen( match_string );
- end++; /* Skip the '*' */
- while( (*end) /* Not the end of string. */
- && (*end != ')') /* Not the end of the pattern. */
- && (*end != '*') ) /* Not a wildcard. */
- *np++ = *end++;
- }
- if( !*end )
- {
- start = end;
- continue; /* Always check for the end. */
- }
- *np++ = '\0'; /* NULL terminate it. */
- DEBUG(5,("End of second in pair '%s'\n", end));
- pstrcpy( s, new_string ); /* Substitute with the new name. */
- DEBUG( 5, ("s is now '%s'\n", s) );
- }
- start = end; /* Skip a bit which cannot be wanted anymore. */
- start++;
- }
- } /* do_fwd_mangled_map */
+BOOL mangle_is_8_3_wildcards(const char *fname, BOOL check_case)
+{
+ return mangle_fns->is_8_3(fname, check_case, True);
+}
+
+/*
+ try to reverse map a 8.3 name to the original filename. This doesn't have to
+ always succeed, as the directory handling code in smbd will scan the directory
+ looking for a matching name if it doesn't. It should succeed most of the time
+ or there will be a huge performance penalty
+*/
+BOOL mangle_check_cache(char *s)
+{
+ return mangle_fns->check_cache(s);
+}
-/*****************************************************************************
- * do the actual mangling to 8.3 format
- * the buffer must be able to hold 13 characters (including the null)
- *****************************************************************************
+/*
+ map a long filename to a 8.3 name.
*/
-void mangle_name_83( char *s)
- {
- int csum;
- char *p;
- char extension[4];
- char base[9];
- int baselen = 0;
- int extlen = 0;
- int skip;
-
- extension[0] = 0;
- base[0] = 0;
-
- p = strrchr(s,'.');
- if( p && (strlen(p+1) < (size_t)4) )
- {
- BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */
-
- if( all_normal && p[1] != 0 )
- {
- *p = 0;
- csum = str_checksum( s );
- *p = '.';
- }
- else
- csum = str_checksum(s);
- }
- else
- csum = str_checksum(s);
-
- strupper( s );
-
- DEBUG( 5, ("Mangling name %s to ",s) );
-
- if( p )
- {
- if( p == s )
- safe_strcpy( extension, "___", 3 );
- else
- {
- *p++ = 0;
- while( *p && extlen < 3 )
- {
- skip = get_character_len( *p );
- switch( skip )
- {
- case 2:
- if( extlen < 2 )
- {
- extension[extlen++] = p[0];
- extension[extlen++] = p[1];
- }
- else
- {
- extension[extlen++] = mangle( (unsigned char)*p );
- }
- p += 2;
- break;
- case 1:
- extension[extlen++] = p[0];
- p++;
- break;
- default:
- if( isdoschar (*p) && *p != '.' )
- extension[extlen++] = p[0];
- p++;
- break;
- }
- }
- extension[extlen] = 0;
- }
- }
-
- p = s;
-
- while( *p && baselen < 5 )
- {
- skip = get_character_len(*p);
- switch( skip )
- {
- case 2:
- if( baselen < 4 )
- {
- base[baselen++] = p[0];
- base[baselen++] = p[1];
- }
- else
- {
- base[baselen++] = mangle( (unsigned char)*p );
- }
- p += 2;
- break;
- case 1:
- base[baselen++] = p[0];
- p++;
- break;
- default:
- if( isdoschar( *p ) && *p != '.' )
- base[baselen++] = p[0];
- p++;
- break;
- }
- }
- base[baselen] = 0;
-
- csum = csum % (MANGLE_BASE*MANGLE_BASE);
- (void)slprintf(s, 12, "%s%c%c%c",
- base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
-
- if( *extension )
- {
- (void)pstrcat( s, "." );
- (void)pstrcat( s, extension );
- }
-
- DEBUG( 5, ( "%s\n", s ) );
-
- } /* mangle_name_83 */
-
-/*****************************************************************************
- * Convert a filename to DOS format. Return True if successful.
- *
- * Input: OutName - Source *and* destination buffer.
- *
- * NOTE that OutName must point to a memory space that
- * is at least 13 bytes in size!
- *
- * need83 - If False, name mangling will be skipped unless the
- * name contains illegal characters. Mapping will still
- * be done, if appropriate. This is probably used to
- * signal that a client does not require name mangling,
- * thus skipping the name mangling even on shares which
- * have name-mangling turned on.
- * cache83 - If False, the mangled name cache will not be updated.
- * This is usually used to prevent that we overwrite
- * a conflicting cache entry prematurely, i.e. before
- * we know whether the client is really interested in the
- * current name. (See PR#13758). UKD.
- * snum - Share number. This identifies the share in which the
- * name exists.
- *
- * Output: Returns False only if the name wanted mangling but the share does
- * not have name mangling turned on.
- *
- * ****************************************************************************
- */
-BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
+void mangle_map(char *OutName, BOOL need83, BOOL cache83, int snum)
{
- char *map;
- DEBUG(5,("name_map_mangle( %s, need83 = %s, cache83 = %s, %d )\n", OutName,
- need83 ? "True" : "False", cache83 ? "True" : "False", snum));
-
-#ifdef MANGLE_LONG_FILENAMES
- if( !need83 && is_illegal_name(OutName) )
- need83 = True;
-#endif
-
- /* apply any name mappings */
- map = lp_mangled_map(snum);
-
- if (map && *map) {
- do_fwd_mangled_map( OutName, map );
- }
-
- /* check if it's already in 8.3 format */
- if (need83 && !is_8_3(OutName, True)) {
- char *tmp = NULL;
-
- if (!lp_manglednames(snum)) {
- return(False);
- }
-
- /* mangle it into 8.3 */
- if (cache83)
- tmp = strdup(OutName);
-
- mangle_name_83(OutName);
-
- if(tmp != NULL) {
- cache_mangled_name(OutName, tmp);
- SAFE_FREE(tmp);
+ /* name mangling can be disabled for speed, in which case
+ we just truncate the string */
+ if (!lp_manglednames(snum)) {
+ if (need83) {
+ string_truncate(OutName, 12);
}
+ return;
}
- DEBUG(5,("name_map_mangle() ==> [%s]\n", OutName));
- return(True);
-} /* name_map_mangle */
-
+ /* invoke the inane "mangled map" code */
+ mangle_map_filename(OutName, snum);
+ mangle_fns->name_map(OutName, need83, cache83);
+}
diff --git a/source/smbd/mangle_hash.c b/source/smbd/mangle_hash.c
index 1d4697474ce..7fef891f633 100644
--- a/source/smbd/mangle_hash.c
+++ b/source/smbd/mangle_hash.c
@@ -1,9 +1,8 @@
/*
- Unix SMB/CIFS implementation.
+ Unix SMB/Netbios implementation.
+ Version 1.9.
Name mangling
- Copyright (C) Andrew Tridgell 1992-2002
- Copyright (C) Simo Sorce 2001
- Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Andrew Tridgell 1992-1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,16 +19,15 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
/* -------------------------------------------------------------------------- **
* Notable problems...
*
* March/April 1998 CRH
* - Many of the functions in this module overwrite string buffers passed to
* them. This causes a variety of problems and is, generally speaking,
- * dangerous and scarry. See the kludge notes in name_map()
+ * dangerous and scarry. See the kludge notes in name_map_mangle()
* below.
- * - It seems that something is calling name_map() twice. The
+ * - It seems that something is calling name_map_mangle() twice. The
* first call is probably some sort of test. Names which contain
* illegal characters are being doubly mangled. I'm not sure, but
* I'm guessing the problem is in server.c.
@@ -86,11 +84,11 @@ extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */
*
* isbasecahr() - Given a character, check the chartest array to see
* if that character is in the basechars set. This is
- * faster than using strchr_m().
+ * faster than using strchr().
*
* isillegal() - Given a character, check the chartest array to see
* if that character is in the illegal characters set.
- * This is faster than using strchr_m().
+ * This is faster than using strchr().
*
* mangled_cache - Cache header used for storing mangled -> original
* reverse maps.
@@ -128,252 +126,158 @@ static BOOL ct_initialized = False;
static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } };
static BOOL mc_initialized = False;
#define MANGLED_CACHE_MAX_ENTRIES 1024
-#define MANGLED_CACHE_MAX_MEMORY 0
+#define MANGLED_CACHE_MAX_MEMORY 0
+
/* -------------------------------------------------------------------------- **
- * External Variables...
+ * Functions...
*/
-extern int case_default; /* Are conforming 8.3 names all upper or lower? */
-extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */
-
-/* -------------------------------------------------------------------- */
-
-static NTSTATUS has_valid_chars(const smb_ucs2_t *s, BOOL allow_wildcards)
-{
- if (!s || !*s)
- return NT_STATUS_INVALID_PARAMETER;
-
- /* CHECK: this should not be necessary if the ms wild chars
- are not valid in valid.dat --- simo */
- if (!allow_wildcards && ms_has_wild_w(s))
- return NT_STATUS_UNSUCCESSFUL;
-
- while (*s) {
- if(!isvalid83_w(*s))
- return NT_STATUS_UNSUCCESSFUL;
- s++;
- }
-
- return NT_STATUS_OK;
-}
-
-/* return False if something fail and
- * return 2 alloced unicode strings that contain prefix and extension
+/* ************************************************************************** **
+ * Initialize the static character test array.
+ *
+ * Input: none
+ *
+ * Output: none
+ *
+ * Notes: This function changes (loads) the contents of the <chartest>
+ * array. The scope of <chartest> is this file.
+ *
+ * ************************************************************************** **
*/
+static void init_chartest( void )
+ {
+ char *illegalchars = "*\\/?<>|\":";
+ unsigned char *s;
+
+ memset( (char *)chartest, '\0', 256 );
-static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix,
- smb_ucs2_t **extension, BOOL allow_wildcards)
-{
- size_t ext_len;
- smb_ucs2_t *p;
+ for( s = (unsigned char *)illegalchars; *s; s++ )
+ chartest[*s] = ILLEGAL_MASK;
- *extension = 0;
- *prefix = strdup_w(ucs2_string);
- if (!*prefix) {
- return NT_STATUS_NO_MEMORY;
- }
- if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) {
- ext_len = strlen_w(p+1);
- if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) &&
- (NT_STATUS_IS_OK(has_valid_chars(p+1,allow_wildcards)))) /* check extension */ {
- *p = 0;
- *extension = strdup_w(p+1);
- if (!*extension) {
- SAFE_FREE(*prefix);
- return NT_STATUS_NO_MEMORY;
- }
- }
- }
- return NT_STATUS_OK;
-}
+ for( s = (unsigned char *)basechars; *s; s++ )
+ chartest[*s] |= BASECHAR_MASK;
+
+ ct_initialized = True;
+ } /* init_chartest */
/* ************************************************************************** **
- * Return NT_STATUS_UNSUCCESSFUL if a name is a special msdos reserved name.
+ * Return True if a name is a special msdos reserved name.
*
* Input: fname - String containing the name to be tested.
*
- * Output: NT_STATUS_UNSUCCESSFUL, if the name matches one of the list of reserved names.
+ * Output: True, if the name matches one of the list of reserved names.
*
* Notes: This is a static function called by is_8_3(), below.
*
* ************************************************************************** **
*/
-
-static NTSTATUS is_valid_name(const smb_ucs2_t *fname, BOOL allow_wildcards)
-{
- smb_ucs2_t *str, *p;
- NTSTATUS ret = NT_STATUS_OK;
-
- if (!fname || !*fname)
- return NT_STATUS_INVALID_PARAMETER;
-
- /* . and .. are valid names. */
- if (strcmp_wa(fname, ".")==0 || strcmp_wa(fname, "..")==0)
- return NT_STATUS_OK;
-
- /* Name cannot start with '.' */
- if (*fname == UCS2_CHAR('.'))
- return NT_STATUS_UNSUCCESSFUL;
-
- ret = has_valid_chars(fname, allow_wildcards);
- if (NT_STATUS_IS_ERR(ret))
- return ret;
-
- str = strdup_w(fname);
- p = strchr_w(str, UCS2_CHAR('.'));
- if (p && p[1] == UCS2_CHAR(0)) {
- /* Name cannot end in '.' */
- SAFE_FREE(str);
- return NT_STATUS_UNSUCCESSFUL;
- }
- if (p) *p = 0;
- strupper_w(str);
- p = &(str[1]);
-
- switch(str[0])
- {
- case UCS2_CHAR('A'):
- if(strcmp_wa(p, "UX") == 0)
- ret = NT_STATUS_UNSUCCESSFUL;
- break;
- case UCS2_CHAR('C'):
- if((strcmp_wa(p, "LOCK$") == 0)
- || (strcmp_wa(p, "ON") == 0)
- || (strcmp_wa(p, "OM1") == 0)
- || (strcmp_wa(p, "OM2") == 0)
- || (strcmp_wa(p, "OM3") == 0)
- || (strcmp_wa(p, "OM4") == 0)
- )
- ret = NT_STATUS_UNSUCCESSFUL;
- break;
- case UCS2_CHAR('L'):
- if((strcmp_wa(p, "PT1") == 0)
- || (strcmp_wa(p, "PT2") == 0)
- || (strcmp_wa(p, "PT3") == 0)
- )
- ret = NT_STATUS_UNSUCCESSFUL;
- break;
- case UCS2_CHAR('N'):
- if(strcmp_wa(p, "UL") == 0)
- ret = NT_STATUS_UNSUCCESSFUL;
- break;
- case UCS2_CHAR('P'):
- if(strcmp_wa(p, "RN") == 0)
- ret = NT_STATUS_UNSUCCESSFUL;
- break;
- default:
- break;
- }
-
- SAFE_FREE(str);
- return ret;
-}
-
-static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, BOOL allow_wildcards)
-{
- smb_ucs2_t *pref = 0, *ext = 0;
- size_t plen;
- NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-
- if (!fname || !*fname)
- return NT_STATUS_INVALID_PARAMETER;
-
- if (strlen_w(fname) > 12)
- return NT_STATUS_UNSUCCESSFUL;
-
- if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
- return NT_STATUS_OK;
-
- if (NT_STATUS_IS_ERR(is_valid_name(fname, allow_wildcards)))
- goto done;
-
- if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext, allow_wildcards)))
- goto done;
- plen = strlen_w(pref);
-
- if (strchr_wa(pref, '.'))
- goto done;
- if (plen < 1 || plen > 8)
- goto done;
- if (ext && (strlen_w(ext) > 3))
- goto done;
-
- ret = NT_STATUS_OK;
-
-done:
- SAFE_FREE(pref);
- SAFE_FREE(ext);
- return ret;
-}
-
-static BOOL is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards)
-{
- const char *f;
- smb_ucs2_t *ucs2name;
- NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-
- if (!fname || !*fname)
- return False;
- if ((f = strrchr(fname, '/')) == NULL)
- f = fname;
- else
- f++;
-
- if (strlen(f) > 12)
- return False;
-
- ucs2name = acnv_uxu2(f);
- if (!ucs2name) {
- DEBUG(0,("is_8_3: internal error acnv_uxu2() failed!\n"));
- goto done;
- }
-
- ret = is_8_3_w(ucs2name, allow_wildcards);
-
-done:
- SAFE_FREE(ucs2name);
-
- if (!NT_STATUS_IS_OK(ret)) {
- return False;
- }
-
- return True;
-}
-
-
-
-/* -------------------------------------------------------------------------- **
- * Functions...
- */
+static BOOL is_reserved_msdos( char *fname )
+ {
+ char upperFname[13];
+ char *p;
+
+ StrnCpy (upperFname, fname, 12);
+
+ /* lpt1.txt and con.txt etc are also illegal */
+ p = strchr(upperFname,'.');
+ if( p )
+ *p = '\0';
+
+ strupper( upperFname );
+ p = upperFname + 1;
+ switch( upperFname[0] )
+ {
+ case 'A':
+ if( 0 == strcmp( p, "UX" ) )
+ return( True );
+ break;
+ case 'C':
+ if( (0 == strcmp( p, "LOCK$" ))
+ || (0 == strcmp( p, "ON" ))
+ || (0 == strcmp( p, "OM1" ))
+ || (0 == strcmp( p, "OM2" ))
+ || (0 == strcmp( p, "OM3" ))
+ || (0 == strcmp( p, "OM4" ))
+ )
+ return( True );
+ break;
+ case 'L':
+ if( (0 == strcmp( p, "PT1" ))
+ || (0 == strcmp( p, "PT2" ))
+ || (0 == strcmp( p, "PT3" ))
+ )
+ return( True );
+ break;
+ case 'N':
+ if( 0 == strcmp( p, "UL" ) )
+ return( True );
+ break;
+ case 'P':
+ if( 0 == strcmp( p, "RN" ) )
+ return( True );
+ break;
+ }
+
+ return( False );
+ } /* is_reserved_msdos */
/* ************************************************************************** **
- * Initialize the static character test array.
+ * Determine whether or not a given name contains illegal characters, even
+ * long names.
*
- * Input: none
+ * Input: name - The name to be tested.
*
- * Output: none
+ * Output: True if an illegal character was found in <name>, else False.
*
- * Notes: This function changes (loads) the contents of the <chartest>
- * array. The scope of <chartest> is this file.
+ * Notes: This is used to test a name on the host system, long or short,
+ * for characters that would be illegal on most client systems,
+ * particularly DOS and Windows systems. Unix and AmigaOS, for
+ * example, allow a filenames which contain such oddities as
+ * quotes ("). If a name is found which does contain an illegal
+ * character, it is mangled even if it conforms to the 8.3
+ * format.
*
* ************************************************************************** **
*/
-static void init_chartest( void )
-{
- char *illegalchars = "*\\/?<>|\":";
- unsigned char *s;
-
- memset( (char *)chartest, '\0', 256 );
-
- for( s = (unsigned char *)illegalchars; *s; s++ )
- chartest[*s] = ILLEGAL_MASK;
-
- for( s = (unsigned char *)basechars; *s; s++ )
- chartest[*s] |= BASECHAR_MASK;
-
- ct_initialized = True;
-}
+static BOOL is_illegal_name( char *name )
+ {
+ unsigned char *s;
+ int skip;
+ int namelen;
+
+ if( !name )
+ return( True );
+
+ if( !ct_initialized )
+ init_chartest();
+
+ namelen = strlen(name);
+ if (namelen &&
+ name[namelen-1] == '.' &&
+ !strequal(name, ".") &&
+ !strequal(name, ".."))
+ return True;
+
+ s = (unsigned char *)name;
+ while( *s )
+ {
+ skip = get_character_len( *s );
+ if( skip != 0 )
+ {
+ s += skip;
+ }
+ else
+ {
+ if( isillegal( *s ) )
+ return( True );
+ else
+ s++;
+ }
+ }
+
+ return( False );
+ } /* is_illegal_name */
/* ************************************************************************** **
* Return True if the name *could be* a mangled name.
@@ -392,22 +296,152 @@ static void init_chartest( void )
*
* ************************************************************************** **
*/
-static BOOL is_mangled(const char *s)
+static BOOL is_mangled( const char *s )
{
char *magic;
+ BOOL ret = False;
if( !ct_initialized )
init_chartest();
- magic = strchr_m( s, magic_char );
- while( magic && magic[1] && magic[2] ) { /* 3 chars, 1st is magic. */
+ magic = strchr( s, magic_char );
+ while( magic && magic[1] && magic[2] ) {
+ /* 3 chars, 1st is magic. */
if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */
&& isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */
&& isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */
- return( True ); /* If all above, then true, */
- magic = strchr_m( magic+1, magic_char ); /* else seek next magic. */
+ ret = ( True ); /* If all above, then true, */
+ magic = strchr( magic+1, magic_char ); /* else seek next magic. */
+ }
+
+ DEBUG(10,("is_mangled: %s : %s\n", s, ret ? "True" : "False"));
+
+ return ret;
+} /* is_mangled */
+
+static BOOL is_ms_wildchar(const char c)
+{
+ switch(c) {
+ case '*':
+ case '?':
+ case '<':
+ case '>':
+ case '"':
+ return True;
+ default:
+ return False;
}
- return( False );
+}
+
+/* ************************************************************************** **
+ * Return True if the name is a valid DOS name in 8.3 DOS format.
+ *
+ * Input: fname - File name to be checked.
+ * check_case - If True, and if case_mangle is True, then the
+ * name will be checked to see if all characters
+ * are the correct case. See case_mangle and
+ * case_default above.
+ * allow_wildcards - If True dos wildcard characters *?<>" are allowed as 8.3.
+ *
+ * Output: True if the name is a valid DOS name, else False.
+ *
+ * ************************************************************************** **
+ */
+
+static BOOL is_8_3( const char *cfname, BOOL check_case, BOOL allow_wildcards )
+{
+ int len;
+ int l;
+ int skip;
+ char *p;
+ char *dot_pos;
+ char *slash_pos;
+ char *fname = (char *)cfname;
+
+ slash_pos = strrchr( fname, '/' );
+
+ /* If there is a directory path, skip it. */
+ if( slash_pos )
+ fname = slash_pos + 1;
+ len = strlen( fname );
+
+ DEBUG( 5, ( "Checking %s for 8.3\n", fname ) );
+
+ /* Can't be 0 chars or longer than 12 chars */
+ if( (len == 0) || (len > 12) )
+ return( False );
+
+ /* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
+ if( is_reserved_msdos( fname ) )
+ return( False );
+
+ /* Check that all characters are the correct case, if asked to do so. */
+ if( check_case && case_mangle ) {
+ switch( case_default ) {
+ case CASE_LOWER:
+ if( strhasupper( fname ) )
+ return(False);
+ break;
+ case CASE_UPPER:
+ if( strhaslower( fname ) )
+ return(False);
+ break;
+ }
+ }
+
+ /* Can't contain invalid dos chars */
+ /* Windows use the ANSI charset.
+ But filenames are translated in the PC charset.
+ This Translation may be more or less relaxed depending
+ the Windows application. */
+
+ /* %%% A nice improvment to name mangling would be to translate
+ filename to ANSI charset on the smb server host */
+
+ p = fname;
+ dot_pos = NULL;
+ while( *p ) {
+ if( (skip = get_character_len( *p )) != 0 )
+ p += skip;
+ else {
+ if( *p == '.' && !dot_pos )
+ dot_pos = (char *)p;
+ else {
+ if( !isdoschar( *p )) {
+ if (!allow_wildcards)
+ return False;
+ if (!is_ms_wildchar(*p))
+ return False;
+ }
+ }
+ p++;
+ }
+ }
+
+ /* no dot and less than 9 means OK */
+ if( !dot_pos )
+ return( len <= 8 );
+
+ l = PTR_DIFF( dot_pos, fname );
+
+ /* base must be at least 1 char except special cases . and .. */
+ if( l == 0 )
+ return( 0 == strcmp( fname, "." ) || 0 == strcmp( fname, ".." ) );
+
+ /* base can't be greater than 8 */
+ if( l > 8 )
+ return( False );
+
+ /* extension must be between 1 and 3 */
+ if( (len - l < 2 ) || (len - l > 4) )
+ return( False );
+
+ /* extensions may not have a dot */
+ if( strchr( dot_pos+1, '.' ) )
+ return( False );
+
+ /* must be in 8.3 format */
+ return( True );
}
/* ************************************************************************** **
@@ -429,11 +463,14 @@ static BOOL is_mangled(const char *s)
*
* ************************************************************************** **
*/
+
static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
{
char *Key1 = (char *)ItemPtr;
char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
+ DEBUG(100,("cache_compare: %s %s\n", Key1, Key2));
+
return( StrCaseCmp( Key1, Key2 ) );
}
@@ -450,6 +487,7 @@ static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
*
* ************************************************************************** **
*/
+
static void cache_free_entry( ubi_trNodePtr WarrenZevon )
{
ZERO_STRUCTP(WarrenZevon);
@@ -473,22 +511,22 @@ static void cache_free_entry( ubi_trNodePtr WarrenZevon )
* ************************************************************************** **
*/
-static void mangle_reset( void )
+static void reset_mangled_cache( void )
{
if( !mc_initialized ) {
(void)ubi_cacheInit( mangled_cache,
- cache_compare,
- cache_free_entry,
- MANGLED_CACHE_MAX_ENTRIES,
- MANGLED_CACHE_MAX_MEMORY );
+ cache_compare,
+ cache_free_entry,
+ MANGLED_CACHE_MAX_ENTRIES,
+ MANGLED_CACHE_MAX_MEMORY );
mc_initialized = True;
} else {
(void)ubi_cacheClear( mangled_cache );
}
/*
- (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() );
- (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() );
+ (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() );
+ (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() );
*/
}
@@ -518,47 +556,49 @@ static void mangle_reset( void )
*/
static void cache_mangled_name( char *mangled_name, char *raw_name )
{
- ubi_cacheEntryPtr new_entry;
- char *s1;
- char *s2;
- size_t mangled_len;
- size_t raw_len;
- size_t i;
-
- /* If the cache isn't initialized, give up. */
- if( !mc_initialized )
- return;
-
- /* Init the string lengths. */
- mangled_len = strlen( mangled_name );
- raw_len = strlen( raw_name );
-
- /* See if the extensions are unmangled. If so, store the entry
- * without the extension, thus creating a "group" reverse map.
- */
- s1 = strrchr( mangled_name, '.' );
- if( s1 && (s2 = strrchr( raw_name, '.' )) ) {
- i = 1;
- while( s1[i] && (tolower( s1[i] ) == s2[i]) )
- i++;
- if( !s1[i] && !s2[i] ) {
- mangled_len -= i;
- raw_len -= i;
- }
- }
-
- /* Allocate a new cache entry. If the allocation fails, just return. */
- i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
- new_entry = malloc( i );
- if( !new_entry )
- return;
-
- /* Fill the new cache entry, and add it to the cache. */
- s1 = (char *)(new_entry + 1);
- s2 = (char *)&(s1[mangled_len + 1]);
- (void)StrnCpy( s1, mangled_name, mangled_len );
- (void)StrnCpy( s2, raw_name, raw_len );
- ubi_cachePut( mangled_cache, i, new_entry, s1 );
+ ubi_cacheEntryPtr new_entry;
+ char *s1;
+ char *s2;
+ size_t mangled_len;
+ size_t raw_len;
+ size_t i;
+
+ /* If the cache isn't initialized, give up. */
+ if( !mc_initialized )
+ return;
+
+ /* Init the string lengths. */
+ mangled_len = strlen( mangled_name );
+ raw_len = strlen( raw_name );
+
+ /* See if the extensions are unmangled. If so, store the entry
+ * without the extension, thus creating a "group" reverse map.
+ */
+ s1 = strrchr( mangled_name, '.' );
+ if( s1 && (s2 = strrchr( raw_name, '.' )) )
+ {
+ i = 1;
+ while( s1[i] && (tolower( s1[i] ) == s2[i]) )
+ i++;
+ if( !s1[i] && !s2[i] )
+ {
+ mangled_len -= i;
+ raw_len -= i;
+ }
+ }
+
+ /* Allocate a new cache entry. If the allocation fails, just return. */
+ i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
+ new_entry = malloc( i );
+ if( !new_entry )
+ return;
+
+ /* Fill the new cache entry, and add it to the cache. */
+ s1 = (char *)(new_entry + 1);
+ s2 = (char *)&(s1[mangled_len + 1]);
+ (void)StrnCpy( s1, mangled_name, mangled_len );
+ (void)StrnCpy( s2, raw_name, raw_len );
+ ubi_cachePut( mangled_cache, i, new_entry, s1 );
}
/* ************************************************************************** **
@@ -576,58 +616,67 @@ static void cache_mangled_name( char *mangled_name, char *raw_name )
* ************************************************************************** **
*/
-static BOOL check_cache( char *s )
+static BOOL check_mangled_cache( char *s )
{
- ubi_cacheEntryPtr FoundPtr;
- char *ext_start = NULL;
- char *found_name;
- char *saved_ext = NULL;
-
- /* If the cache isn't initialized, give up. */
- if( !mc_initialized )
- return( False );
-
- FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
-
- /* If we didn't find the name *with* the extension, try without. */
- if( !FoundPtr ) {
- ext_start = strrchr( s, '.' );
- if( ext_start ) {
- if((saved_ext = strdup(ext_start)) == NULL)
- return False;
-
- *ext_start = '\0';
- FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
- /*
- * At this point s is the name without the
- * extension. We re-add the extension if saved_ext
- * is not null, before freeing saved_ext.
- */
- }
- }
-
- /* Okay, if we haven't found it we're done. */
- if( !FoundPtr ) {
- if(saved_ext) {
- /* Replace the saved_ext as it was truncated. */
- (void)pstrcat( s, saved_ext );
- SAFE_FREE(saved_ext);
- }
- return( False );
- }
-
- /* If we *did* find it, we need to copy it into the string buffer. */
- found_name = (char *)(FoundPtr + 1);
- found_name += (strlen( found_name ) + 1);
-
- (void)pstrcpy( s, found_name );
- if( saved_ext ) {
- /* Replace the saved_ext as it was truncated. */
- (void)pstrcat( s, saved_ext );
- SAFE_FREE(saved_ext);
- }
-
- return( True );
+ ubi_cacheEntryPtr FoundPtr;
+ char *ext_start = NULL;
+ char *found_name;
+ char *saved_ext = NULL;
+
+ /* If the cache isn't initialized, give up. */
+ if( !mc_initialized )
+ return( False );
+
+ FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
+
+ /* If we didn't find the name *with* the extension, try without. */
+ if( !FoundPtr )
+ {
+ ext_start = strrchr( s, '.' );
+ if( ext_start )
+ {
+ if((saved_ext = strdup(ext_start)) == NULL)
+ return False;
+
+ *ext_start = '\0';
+ FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
+ /*
+ * At this point s is the name without the
+ * extension. We re-add the extension if saved_ext
+ * is not null, before freeing saved_ext.
+ */
+ }
+ }
+
+ /* Okay, if we haven't found it we're done. */
+ if( !FoundPtr )
+ {
+ if(saved_ext)
+ {
+ /* Replace the saved_ext as it was truncated. */
+ (void)pstrcat( s, saved_ext );
+ SAFE_FREE(saved_ext);
+ }
+ return( False );
+ }
+
+ /* If we *did* find it, we need to copy it into the string buffer. */
+ found_name = (char *)(FoundPtr + 1);
+ found_name += (strlen( found_name ) + 1);
+
+ DEBUG( 3, ("Found %s on mangled stack ", s) );
+
+ (void)pstrcpy( s, found_name );
+ if( saved_ext )
+ {
+ /* Replace the saved_ext as it was truncated. */
+ (void)pstrcat( s, saved_ext );
+ SAFE_FREE(saved_ext);
+ }
+
+ DEBUG( 3, ("as %s\n", s) );
+
+ return( True );
}
/*****************************************************************************
@@ -635,67 +684,124 @@ static BOOL check_cache( char *s )
* the buffer must be able to hold 13 characters (including the null)
*****************************************************************************
*/
-static void to_8_3(char *s)
+static void mangle_name_83( char *s)
{
- int csum;
- char *p;
- char extension[4];
- char base[9];
- int baselen = 0;
- int extlen = 0;
-
- extension[0] = 0;
- base[0] = 0;
-
- p = strrchr(s,'.');
- if( p && (strlen(p+1) < (size_t)4) ) {
- BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */
-
- if( all_normal && p[1] != 0 ) {
- *p = 0;
- csum = str_checksum( s );
- *p = '.';
- } else
- csum = str_checksum(s);
- } else
- csum = str_checksum(s);
-
- strupper( s );
-
- if( p ) {
- if( p == s )
- safe_strcpy( extension, "___", 3 );
- else {
- *p++ = 0;
- while( *p && extlen < 3 ) {
- if ( *p != '.') {
- extension[extlen++] = p[0];
- }
- p++;
- }
- extension[extlen] = 0;
- }
- }
-
- p = s;
+ int csum;
+ char *p;
+ char extension[4];
+ char base[9];
+ int baselen = 0;
+ int extlen = 0;
+ int skip;
+
+ extension[0] = 0;
+ base[0] = 0;
+
+ p = strrchr(s,'.');
+ if( p && (strlen(p+1) < (size_t)4) )
+ {
+ BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */
+
+ if( all_normal && p[1] != 0 )
+ {
+ *p = 0;
+ csum = str_checksum( s );
+ *p = '.';
+ }
+ else
+ csum = str_checksum(s);
+ }
+ else
+ csum = str_checksum(s);
+
+ strupper( s );
+
+ DEBUG( 5, ("Mangling name %s to ",s) );
+
+ if( p )
+ {
+ if( p == s )
+ safe_strcpy( extension, "___", 3 );
+ else
+ {
+ *p++ = 0;
+ while( *p && extlen < 3 )
+ {
+ skip = get_character_len( *p );
+ switch( skip )
+ {
+ case 2:
+ if( extlen < 2 )
+ {
+ extension[extlen++] = p[0];
+ extension[extlen++] = p[1];
+ }
+ else
+ {
+ extension[extlen++] = mangle( (unsigned char)*p );
+ }
+ p += 2;
+ break;
+ case 1:
+ extension[extlen++] = p[0];
+ p++;
+ break;
+ default:
+ if( isdoschar (*p) && *p != '.' )
+ extension[extlen++] = p[0];
+ p++;
+ break;
+ }
+ }
+ extension[extlen] = 0;
+ }
+ }
+
+ p = s;
+
+ while( *p && baselen < 5 )
+ {
+ skip = get_character_len(*p);
+ switch( skip )
+ {
+ case 2:
+ if( baselen < 4 )
+ {
+ base[baselen++] = p[0];
+ base[baselen++] = p[1];
+ }
+ else
+ {
+ base[baselen++] = mangle( (unsigned char)*p );
+ }
+ p += 2;
+ break;
+ case 1:
+ base[baselen++] = p[0];
+ p++;
+ break;
+ default:
+ if( isdoschar( *p ) && *p != '.' )
+ base[baselen++] = p[0];
+ p++;
+ break;
+ }
+ }
+ base[baselen] = 0;
+
+ csum = csum % (MANGLE_BASE*MANGLE_BASE);
+
+ (void)slprintf(s, 12, "%s%c%c%c",
+ base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
+
+ if( *extension )
+ {
+ (void)pstrcat( s, "." );
+ (void)pstrcat( s, extension );
+ }
+
+ DEBUG( 5, ( "%s\n", s ) );
- while( *p && baselen < 5 ) {
- if (*p != '.') {
- base[baselen++] = p[0];
- }
- p++;
- }
- base[baselen] = 0;
-
- csum = csum % (MANGLE_BASE*MANGLE_BASE);
-
- (void)slprintf(s, 12, "%s%c%c%c",
- base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
-
- if( *extension ) {
- (void)pstrcat( s, "." );
- (void)pstrcat( s, extension );
- }
}
/*****************************************************************************
@@ -717,36 +823,33 @@ static void to_8_3(char *s)
* a conflicting cache entry prematurely, i.e. before
* we know whether the client is really interested in the
* current name. (See PR#13758). UKD.
+ * snum - Share number. This identifies the share in which the
+ * name exists.
*
* Output: Returns False only if the name wanted mangling but the share does
* not have name mangling turned on.
*
* ****************************************************************************
*/
-
-static void name_map(char *OutName, BOOL need83, BOOL cache83)
+static void name_map_mangle(char *OutName, BOOL need83, BOOL cache83)
{
- smb_ucs2_t *OutName_ucs2;
- DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName,
- need83 ? "True" : "False", cache83 ? "True" : "False"));
-
- if (push_ucs2_allocate((void **)&OutName_ucs2, OutName) < 0) {
- DEBUG(0, ("push_ucs2_allocate failed!\n"));
- return;
- }
+ DEBUG(5,("name_map_mangle( %s, need83 = %s, cache83 = %s )\n", OutName,
+ need83 ? "True" : "False", cache83 ? "True" : "False" ));
- if( !need83 && NT_STATUS_IS_ERR(is_valid_name(OutName_ucs2, False)))
+#ifdef MANGLE_LONG_FILENAMES
+ if( !need83 && is_illegal_name(OutName) )
need83 = True;
+#endif
/* check if it's already in 8.3 format */
- if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2, False))) {
+ if (need83 && !is_8_3(OutName, True, False)) {
char *tmp = NULL;
/* mangle it into 8.3 */
if (cache83)
tmp = strdup(OutName);
- to_8_3(OutName);
+ mangle_name_83(OutName);
if(tmp != NULL) {
cache_mangled_name(OutName, tmp);
@@ -754,26 +857,24 @@ static void name_map(char *OutName, BOOL need83, BOOL cache83)
}
}
- DEBUG(5,("name_map() ==> [%s]\n", OutName));
- SAFE_FREE(OutName_ucs2);
+ DEBUG(5,("name_map_mangle() ==> [%s]\n", OutName));
}
/*
- the following provides the abstraction layer to make it easier
- to drop in an alternative mangling implementation
-*/
+ * the following provides the abstraction layer to make it easier
+ * to drop in an alternative mangling implementation
+ * */
static struct mangle_fns mangle_fns = {
is_mangled,
is_8_3,
- mangle_reset,
- check_cache,
- name_map
+ reset_mangled_cache,
+ check_mangled_cache,
+ name_map_mangle
};
/* return the methods for this mangling implementation */
struct mangle_fns *mangle_hash_init(void)
{
- mangle_reset();
-
+ reset_mangled_cache();
return &mangle_fns;
}
diff --git a/source/smbd/mangle_hash2.c b/source/smbd/mangle_hash2.c
index e2c4b43bc37..2074639f26c 100644
--- a/source/smbd/mangle_hash2.c
+++ b/source/smbd/mangle_hash2.c
@@ -53,12 +53,6 @@
#include "includes.h"
-#if 0
-#define M_DEBUG(level, x) DEBUG(level, x)
-#else
-#define M_DEBUG(level, x)
-#endif
-
/* these flags are used to mark characters in as having particular
properties */
#define FLAG_BASECHAR 1
@@ -124,7 +118,7 @@ static u32 mangle_hash(const char *key, unsigned length)
function */
strncpy(str, key, length);
str[length] = 0;
- strupper_m(str);
+ strupper(str);
/* the length of a multi-byte string can change after a strupper_m */
length = strlen(str);
@@ -200,7 +194,7 @@ static BOOL is_mangled_component(const char *name)
{
int len, i;
- M_DEBUG(0,("is_mangled_component %s ?\n", name));
+ DEBUG(10,("is_mangled_component %s ?\n", name));
/* the best distinguishing characteristic is the ~ */
if (name[6] != '~') return False;
@@ -234,7 +228,7 @@ static BOOL is_mangled_component(const char *name)
}
}
- M_DEBUG(0,("is_mangled %s -> yes\n", name));
+ DEBUG(10,("is_mangled %s -> yes\n", name));
return True;
}
@@ -257,7 +251,7 @@ static BOOL is_mangled(const char *name)
const char *p;
const char *s;
- M_DEBUG(0,("is_mangled %s ?\n", name));
+ DEBUG(10,("is_mangled %s ?\n", name));
for (s=name; (p=strchr(s, '/')); s=p+1) {
char *component = strndup(s, PTR_DIFF(p, s));
@@ -367,7 +361,7 @@ static BOOL check_cache(char *name)
/* make sure that this is a mangled name from this cache */
if (!is_mangled(name)) {
- M_DEBUG(0,("check_cache: %s -> not mangled\n", name));
+ DEBUG(10,("check_cache: %s -> not mangled\n", name));
return False;
}
@@ -382,7 +376,7 @@ static BOOL check_cache(char *name)
/* now look in the prefix cache for that hash */
prefix = cache_lookup(hash);
if (!prefix) {
- M_DEBUG(0,("check_cache: %s -> %08X -> not found\n", name, hash));
+ DEBUG(10,("check_cache: %s -> %08X -> not found\n", name, hash));
return False;
}
@@ -395,10 +389,10 @@ static BOOL check_cache(char *name)
}
if (extension[0]) {
- M_DEBUG(0,("check_cache: %s -> %s.%s\n", name, prefix, extension));
+ DEBUG(10,("check_cache: %s -> %s.%s\n", name, prefix, extension));
slprintf(name, sizeof(fstring), "%s.%s", prefix, extension);
} else {
- M_DEBUG(0,("check_cache: %s -> %s\n", name, prefix));
+ DEBUG(10,("check_cache: %s -> %s\n", name, prefix));
fstrcpy(name, prefix);
}
@@ -573,7 +567,7 @@ static void name_map(char *name, BOOL need83, BOOL cache83)
cache_insert(name, prefix_len, hash);
}
- M_DEBUG(0,("name_map: %s -> %08X -> %s (cache=%d)\n",
+ DEBUG(10,("name_map: %s -> %08X -> %s (cache=%d)\n",
name, hash, new_name, cache83));
/* and overwrite the old name */
diff --git a/source/smbd/mangle_map.c b/source/smbd/mangle_map.c
index 71d93407181..372ddc0bd49 100644
--- a/source/smbd/mangle_map.c
+++ b/source/smbd/mangle_map.c
@@ -127,7 +127,7 @@ static char *map_filename( char *s, /* This is null terminated */
*/
static void mangled_map(char *s, const char *MangledMap)
{
- char *start=MangledMap; /* Use this to search for mappings. */
+ char *start=(char*)MangledMap; /* Use this to search for mappings. */
char *end; /* Used to find the end of strings. */
char *match_string;
pstring new_string; /* Make up the result here. */
diff --git a/source/smbd/notify_kernel.c b/source/smbd/notify_kernel.c
index beaa66b1ba3..372416c0ee9 100644
--- a/source/smbd/notify_kernel.c
+++ b/source/smbd/notify_kernel.c
@@ -23,9 +23,9 @@
#if HAVE_KERNEL_CHANGE_NOTIFY
-static VOLATILE sig_atomic_t fd_pending;
-static VOLATILE sig_atomic_t signals_received;
-static VOLATILE sig_atomic_t signals_processed;
+#define FD_PENDING_SIZE 20
+static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
+static SIG_ATOMIC_T signals_received;
#ifndef DN_ACCESS
#define DN_ACCESS 0x00000001 /* File accessed in directory */
@@ -54,70 +54,100 @@ static VOLATILE sig_atomic_t signals_processed;
This is the structure to keep the information needed to
determine if a directory has changed.
*****************************************************************************/
+
struct change_data {
int directory_handle;
};
/****************************************************************************
-the signal handler for change notify
+ The signal handler for change notify.
+ The Linux kernel has a bug in that we should be able to block any
+ further delivery of RT signals until the kernel_check_notify() function
+ unblocks them, but it seems that any signal mask we're setting here is
+ being overwritten on exit from this handler. I should create a standalone
+ test case for the kernel hackers. JRA.
*****************************************************************************/
+
static void signal_handler(int sig, siginfo_t *info, void *unused)
{
- BlockSignals(True, sig);
- fd_pending = (sig_atomic_t)info->si_fd;
- signals_received++;
+ if (signals_received < FD_PENDING_SIZE - 1) {
+ fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd;
+ signals_received++;
+ } /* Else signal is lost. */
sys_select_signal();
}
-
-
/****************************************************************************
Check if a change notify should be issued.
time non-zero means timeout check (used for hash). Ignore this (async method
where time is zero will be used instead).
*****************************************************************************/
+
static BOOL kernel_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
{
struct change_data *data = (struct change_data *)datap;
+ int i;
+ BOOL ret = False;
if (t)
return False;
- if (data->directory_handle != (int)fd_pending) return False;
-
- DEBUG(3,("kernel change notify on %s fd=%d\n", path, (int)fd_pending));
-
- close((int)fd_pending);
- fd_pending = (sig_atomic_t)-1;
- data->directory_handle = -1;
- signals_processed++;
+ BlockSignals(True, RT_SIGNAL_NOTIFY);
+ for (i = 0; i < signals_received; i++) {
+ if (data->directory_handle == (int)fd_pending_array[i]) {
+ DEBUG(3,("kernel_check_notify: kernel change notify on %s fd[%d]=%d (signals_received=%d)\n",
+ path, i, (int)fd_pending_array[i], (int)signals_received ));
+
+ close((int)fd_pending_array[i]);
+ fd_pending_array[i] = (SIG_ATOMIC_T)-1;
+ if (signals_received - i - 1) {
+ memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1],
+ sizeof(SIG_ATOMIC_T)*(signals_received-i-1));
+ }
+ data->directory_handle = -1;
+ signals_received--;
+ ret = True;
+ break;
+ }
+ }
BlockSignals(False, RT_SIGNAL_NOTIFY);
- return True;
+ return ret;
}
/****************************************************************************
-remove a change notify data structure
+ Remove a change notify data structure.
*****************************************************************************/
+
static void kernel_remove_notify(void *datap)
{
struct change_data *data = (struct change_data *)datap;
int fd = data->directory_handle;
if (fd != -1) {
- if (fd == (int)fd_pending) {
- fd_pending = (sig_atomic_t)-1;
- signals_processed++;
- BlockSignals(False, RT_SIGNAL_NOTIFY);
+ int i;
+ BlockSignals(True, RT_SIGNAL_NOTIFY);
+ for (i = 0; i < signals_received; i++) {
+ if (fd == (int)fd_pending_array[i]) {
+ close(fd);
+ fd_pending_array[i] = (SIG_ATOMIC_T)-1;
+ if (signals_received - i - 1) {
+ memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1],
+ sizeof(SIG_ATOMIC_T)*(signals_received-i-1));
+ }
+ data->directory_handle = -1;
+ signals_received--;
+ break;
+ }
}
- close(fd);
+ BlockSignals(False, RT_SIGNAL_NOTIFY);
}
SAFE_FREE(data);
- DEBUG(3,("removed kernel change notify fd=%d\n", fd));
+ DEBUG(3,("kernel_remove_notify: fd=%d\n", fd));
}
-
/****************************************************************************
-register a change notify request
+ Register a change notify request.
*****************************************************************************/
+
static void *kernel_register_notify(connection_struct *conn, char *path, uint32 flags)
{
struct change_data data;
@@ -162,22 +192,24 @@ static void *kernel_register_notify(connection_struct *conn, char *path, uint32
}
/****************************************************************************
-see if the kernel supports change notify
+ See if the kernel supports change notify.
****************************************************************************/
+
static BOOL kernel_notify_available(void)
{
int fd, ret;
fd = open("/tmp", O_RDONLY);
- if (fd == -1) return False; /* uggh! */
+ if (fd == -1)
+ return False; /* uggh! */
ret = sys_fcntl_long(fd, F_NOTIFY, 0);
close(fd);
return ret == 0;
}
-
/****************************************************************************
-setup kernel based change notify
+ Setup kernel based change notify.
****************************************************************************/
+
struct cnotify_fns *kernel_notify_init(void)
{
static struct cnotify_fns cnotify;
@@ -191,7 +223,8 @@ struct cnotify_fns *kernel_notify_init(void)
return NULL;
}
- if (!kernel_notify_available()) return NULL;
+ if (!kernel_notify_available())
+ return NULL;
cnotify.register_notify = kernel_register_notify;
cnotify.check_notify = kernel_check_notify;
@@ -201,7 +234,6 @@ struct cnotify_fns *kernel_notify_init(void)
return &cnotify;
}
-
#else
void notify_kernel_dummy(void) {}
#endif /* HAVE_KERNEL_CHANGE_NOTIFY */
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index c05be55e39e..f7a49794130 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -1041,9 +1041,9 @@ static BOOL set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security
BOOL ret;
if (sd_len == 0) {
- *pdef_class = ERRDOS;
- *pdef_code = ERRbadaccess;
- return False;
+ *pdef_class = 0;
+ *pdef_code = 0;
+ return True;
}
/*
@@ -1369,7 +1369,7 @@ static int call_nt_transact_create(connection_struct *conn,
* Now try and apply the desired SD.
*/
- if (!set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION, &error_class, &error_code)) {
+ if (sd_len && !set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION, &error_class, &error_code)) {
close_file(fsp,False);
restore_case_semantics(file_attributes);
return ERROR_DOS(error_class, error_code);
@@ -1707,6 +1707,9 @@ static int call_nt_transact_set_security_desc(connection_struct *conn,
DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name,
(unsigned int)security_info_sent ));
+ if (total_data_count == 0)
+ return ERROR_DOS(ERRDOS, ERRbadaccess);
+
if (!set_sd( fsp, data, total_data_count, security_info_sent, &error_class, &error_code))
return ERROR_DOS(error_class, error_code);
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 9f57cb294ca..79330175bbd 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -631,8 +631,8 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fname, (unsigned int)dev, (double)inode));
if (process_exists(broken_entry.pid)) {
- DEBUG(0,("open_mode_check: Existent process %d left active oplock.\n",
- broken_entry.pid ));
+ DEBUG(0,("open_mode_check: Existent process %u left active oplock.\n",
+ (unsigned int)broken_entry.pid ));
}
if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) {
diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c
index dbd7b63d060..f36875fc4a9 100644
--- a/source/smbd/oplock.c
+++ b/source/smbd/oplock.c
@@ -73,34 +73,69 @@ BOOL oplock_message_waiting(fd_set *fds)
****************************************************************************/
-BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout)
+BOOL receive_local_message( char *buffer, int buffer_len, int timeout)
{
struct sockaddr_in from;
- int fromlen = sizeof(from);
+ socklen_t fromlen = sizeof(from);
int32 msg_len = 0;
+ fd_set fds;
+ int selrtn = -1;
smb_read_error = 0;
+ FD_ZERO(&fds);
- if(timeout != 0) {
+ /*
+ * We need to check for kernel oplocks before going into the select
+ * here, as the EINTR generated by the linux kernel oplock may have
+ * already been eaten. JRA.
+ */
+
+ if (koplocks && koplocks->msg_waiting(&fds)) {
+ return koplocks->receive_message(&fds, buffer, buffer_len);
+ }
+
+ while (timeout > 0 && selrtn == -1) {
struct timeval to;
- int selrtn;
int maxfd = oplock_sock;
+ time_t starttime = time(NULL);
- if (koplocks && koplocks->notification_fd != -1) {
- FD_SET(koplocks->notification_fd, fds);
- maxfd = MAX(maxfd, koplocks->notification_fd);
- }
+ FD_ZERO(&fds);
+ maxfd = setup_oplock_select_set(&fds);
to.tv_sec = timeout / 1000;
to.tv_usec = (timeout % 1000) * 1000;
- selrtn = sys_select(maxfd+1,fds,NULL,NULL,&to);
+ DEBUG(5,("receive_local_message: doing select with timeout of %d ms\n", timeout));
+
+ selrtn = sys_select(maxfd+1,&fds,NULL,NULL,&to);
if (selrtn == -1 && errno == EINTR) {
+
/* could be a kernel oplock interrupt */
- if (koplocks && koplocks->msg_waiting(fds)) {
- return koplocks->receive_message(fds, buffer, buffer_len);
+ if (koplocks && koplocks->msg_waiting(&fds)) {
+ return koplocks->receive_message(&fds, buffer, buffer_len);
+ }
+
+ /*
+ * Linux 2.0.x seems to have a bug in that
+ * it can return -1, EINTR with a timeout of zero.
+ * Make sure we bail out here with a read timeout
+ * if we got EINTR on a timeout of 1 or less.
+ */
+
+ if (timeout <= 1) {
+ smb_read_error = READ_TIMEOUT;
+ return False;
}
+
+ /* Not a kernel interrupt - could be a SIGUSR1 message. We must restart. */
+ /* We need to decrement the timeout here. */
+ timeout -= ((time(NULL) - starttime)*1000);
+ if (timeout < 0)
+ timeout = 1;
+
+ DEBUG(5,("receive_local_message: EINTR : new timeout %d ms\n", timeout));
+ continue;
}
/* Check if error */
@@ -117,11 +152,11 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
}
}
- if (koplocks && koplocks->msg_waiting(fds)) {
- return koplocks->receive_message(fds, buffer, buffer_len);
+ if (koplocks && koplocks->msg_waiting(&fds)) {
+ return koplocks->receive_message(&fds, buffer, buffer_len);
}
- if (!FD_ISSET(oplock_sock, fds))
+ if (!FD_ISSET(oplock_sock, &fds))
return False;
/*
@@ -133,7 +168,7 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
* Read a loopback udp message.
*/
msg_len = sys_recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN],
- buffer_len - OPBRK_CMD_HEADER_LEN, 0, (struct sockaddr *)&from, &fromlen);
+ buffer_len - OPBRK_CMD_HEADER_LEN, 0, (struct sockaddr *)&from, &fromlen);
if(msg_len < 0) {
DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
@@ -966,16 +1001,8 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n",
char op_break_reply[OPBRK_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
uint16 reply_from_port;
char *reply_msg_start;
- fd_set fds;
-
- FD_ZERO(&fds);
- FD_SET(oplock_sock,&fds);
-
- if (koplocks && koplocks->notification_fd != -1) {
- FD_SET(koplocks->notification_fd, &fds);
- }
- if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),
+ if(receive_local_message(op_break_reply, sizeof(op_break_reply),
time_left ? time_left * 1000 : 1) == False) {
if(smb_read_error == READ_TIMEOUT) {
if( DEBUGLVL( 0 ) ) {
diff --git a/source/smbd/oplock_irix.c b/source/smbd/oplock_irix.c
index 9ca3ecc2609..3576c768fef 100644
--- a/source/smbd/oplock_irix.c
+++ b/source/smbd/oplock_irix.c
@@ -100,7 +100,7 @@ static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_le
*/
if(read(oplock_pipe_read, &dummy, 1) != 1) {
- DEBUG(0,("receive_local_message: read of kernel notification failed. \
+ DEBUG(0,("irix_oplock_receive_message: read of kernel notification failed. \
Error was %s.\n", strerror(errno) ));
smb_read_error = READ_ERROR;
return False;
@@ -113,7 +113,7 @@ Error was %s.\n", strerror(errno) ));
*/
if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
- DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \
+ DEBUG(0,("irix_oplock_receive_message: fcntl of kernel notification failed. \
Error was %s.\n", strerror(errno) ));
if(errno == EAGAIN) {
/*
@@ -132,12 +132,12 @@ Error was %s.\n", strerror(errno) ));
*/
if ((fsp = file_find_di_first((SMB_DEV_T)os.os_dev, (SMB_INO_T)os.os_ino)) == NULL) {
- DEBUG(0,("receive_local_message: unable to find open file with dev = %x, inode = %.0f\n",
+ DEBUG(0,("irix_oplock_receive_message: unable to find open file with dev = %x, inode = %.0f\n",
(unsigned int)os.os_dev, (double)os.os_ino ));
return False;
}
- DEBUG(5,("receive_local_message: kernel oplock break request received for \
+ DEBUG(5,("irix_oplock_receive_message: kernel oplock break request received for \
dev = %x, inode = %.0f\n, file_id = %ul", (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id ));
/*
@@ -167,19 +167,19 @@ static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
{
if (sys_fcntl_long(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) {
if(errno != EAGAIN) {
- DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \
+ DEBUG(0,("irix_set_kernel_oplock: Unable to get kernel oplock on file %s, dev = %x, \
inode = %.0f, file_id = %ul. Error was %s\n",
fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id,
strerror(errno) ));
} else {
- DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
+ DEBUG(5,("irix_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
inode = %.0f, file_id = %ul. Another process had the file open.\n",
fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id ));
}
return False;
}
- DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %ul\n",
+ DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %ul\n",
fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id));
return True;
@@ -197,7 +197,7 @@ static void irix_release_kernel_oplock(files_struct *fsp)
* oplock state of this file.
*/
int state = sys_fcntl_long(fsp->fd, F_OPLKACK, -1);
- dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %ul, has kernel \
+ dbgtext("irix_release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %ul, has kernel \
oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
(double)fsp->inode, fsp->file_id, state );
}
@@ -207,7 +207,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
*/
if(sys_fcntl_long(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) {
if( DEBUGLVL( 0 )) {
- dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
+ dbgtext("irix_release_kernel_oplock: Error when removing kernel oplock on file " );
dbgtext("%s, dev = %x, inode = %.0f, file_id = %ul. Error was %s\n",
fsp->fsp_name, (unsigned int)fsp->dev,
(double)fsp->inode, fsp->file_id, strerror(errno) );
diff --git a/source/smbd/oplock_linux.c b/source/smbd/oplock_linux.c
index 3f22956aa02..f54c6c83e86 100644
--- a/source/smbd/oplock_linux.c
+++ b/source/smbd/oplock_linux.c
@@ -23,9 +23,9 @@
#if HAVE_KERNEL_OPLOCKS_LINUX
-static VOLATILE sig_atomic_t signals_received;
-static VOLATILE sig_atomic_t signals_processed;
-static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal */
+static SIG_ATOMIC_T signals_received;
+#define FD_PENDING_SIZE 100
+static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
#ifndef F_SETLEASE
#define F_SETLEASE 1024
@@ -53,9 +53,10 @@ static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal
static void signal_handler(int sig, siginfo_t *info, void *unused)
{
- BlockSignals(True, sig);
- fd_pending = (sig_atomic_t)info->si_fd;
- signals_received++;
+ if (signals_received < FD_PENDING_SIZE - 1) {
+ fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd;
+ signals_received++;
+ } /* Else signal is lost. */
sys_select_signal();
}
@@ -125,20 +126,28 @@ static int linux_setlease(int fd, int leasetype)
static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
{
- BOOL ret = True;
+ int fd;
struct files_struct *fsp;
- if (signals_received == signals_processed)
- return False;
+ BlockSignals(True, RT_SIGNAL_LEASE);
+ fd = fd_pending_array[0];
+ fsp = file_find_fd(fd);
+ fd_pending_array[0] = (SIG_ATOMIC_T)-1;
+ if (signals_received > 1)
+ memmove((void *)&fd_pending_array[0], (void *)&fd_pending_array[1],
+ sizeof(SIG_ATOMIC_T)*(signals_received-1));
+ signals_received--;
+ /* now we can receive more signals */
+ BlockSignals(False, RT_SIGNAL_LEASE);
- if ((fsp = file_find_fd(fd_pending)) == NULL) {
- DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd_pending));
- ret = False;
- goto out;
+ if (fsp == NULL) {
+ DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd));
+ return False;
}
- DEBUG(3,("receive_local_message: kernel oplock break request received for \
-dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
+ DEBUG(3,("linux_oplock_receive_message: kernel oplock break request received for \
+dev = %x, inode = %.0f fd = %d, fileid = %lu \n", (unsigned int)fsp->dev, (double)fsp->inode,
+ fd, fsp->file_id));
/*
* Create a kernel oplock break message.
@@ -156,13 +165,7 @@ dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode));
memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id));
- out:
- /* now we can receive more signals */
- fd_pending = (sig_atomic_t)-1;
- signals_processed++;
- BlockSignals(False, RT_SIGNAL_LEASE);
-
- return ret;
+ return True;
}
/****************************************************************************
@@ -172,14 +175,14 @@ dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
{
if (linux_setlease(fsp->fd, F_WRLCK) == -1) {
- DEBUG(3,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
+ DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
inode = %.0f. (%s)\n",
fsp->fsp_name, fsp->fd,
(unsigned int)fsp->dev, (double)fsp->inode, strerror(errno)));
return False;
}
- DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n",
+ DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n",
fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id));
return True;
@@ -197,7 +200,7 @@ static void linux_release_kernel_oplock(files_struct *fsp)
* oplock state of this file.
*/
int state = fcntl(fsp->fd, F_GETLEASE, 0);
- dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \
+ dbgtext("linux_release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \
oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
(double)fsp->inode, fsp->file_id, state );
}
@@ -207,7 +210,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
*/
if (linux_setlease(fsp->fd, F_UNLCK) == -1) {
if (DEBUGLVL(0)) {
- dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
+ dbgtext("linux_release_kernel_oplock: Error when removing kernel oplock on file " );
dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n",
fsp->fsp_name, (unsigned int)fsp->dev,
(double)fsp->inode, fsp->file_id, strerror(errno) );
@@ -245,7 +248,7 @@ static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *i
static BOOL linux_oplock_msg_waiting(fd_set *fds)
{
- return signals_processed != signals_received;
+ return signals_received != 0;
}
/****************************************************************************
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
index 6a0aa982b42..cbb28359f94 100644
--- a/source/smbd/posix_acls.c
+++ b/source/smbd/posix_acls.c
@@ -409,7 +409,7 @@ static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
Unpack a SEC_DESC into a UNIX owner and group.
****************************************************************************/
-static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
+static BOOL unpack_nt_owners( int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
{
DOM_SID owner_sid;
DOM_SID grp_sid;
@@ -440,15 +440,15 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp,
if (security_info_sent & OWNER_SECURITY_INFORMATION) {
sid_copy(&owner_sid, psd->owner_sid);
if (!sid_to_uid( &owner_sid, puser, &sid_type)) {
-#if ACL_FORCE_UNMAPPABLE
- /* this allows take ownership to work reasonably */
- extern struct current_user current_user;
- *puser = current_user.uid;
-#else
- DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s.\n",
- sid_string_static(&owner_sid)));
- return False;
-#endif
+ if (lp_force_unknown_acl_user(snum)) {
+ /* this allows take ownership to work reasonably */
+ extern struct current_user current_user;
+ *puser = current_user.uid;
+ } else {
+ DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s.\n",
+ sid_string_static(&owner_sid)));
+ return False;
+ }
}
}
@@ -460,14 +460,14 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp,
if (security_info_sent & GROUP_SECURITY_INFORMATION) {
sid_copy(&grp_sid, psd->grp_sid);
if (!sid_to_gid( &grp_sid, pgrp, &sid_type)) {
-#if ACL_FORCE_UNMAPPABLE
- /* this allows take group ownership to work reasonably */
- extern struct current_user current_user;
- *pgrp = current_user.gid;
-#else
- DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
- return False;
-#endif
+ if (lp_force_unknown_acl_user(snum)) {
+ /* this allows take group ownership to work reasonably */
+ extern struct current_user current_user;
+ *pgrp = current_user.gid;
+ } else {
+ DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
+ return False;
+ }
}
}
@@ -480,7 +480,7 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp,
Ensure the enforced permissions for this share apply.
****************************************************************************/
-static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type)
+static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
{
int snum = SNUM(fsp->conn);
mode_t and_bits = (mode_t)0;
@@ -499,6 +499,10 @@ static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type)
/* Now bounce them into the S_USR space. */
switch(type) {
case S_IRUSR:
+ /* Ensure owner has read access. */
+ pace->perms |= S_IRUSR;
+ if (fsp->is_directory)
+ pace->perms |= (S_IWUSR|S_IXUSR);
and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
break;
@@ -512,7 +516,34 @@ static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type)
break;
}
- return ((perms & and_bits)|or_bits);
+ pace->perms = ((pace->perms & and_bits)|or_bits);
+}
+
+/****************************************************************************
+ Check if a given uid/SID is in a group gid/SID. This is probably very
+ expensive and will need optimisation. A *lot* of optimisation :-). JRA.
+****************************************************************************/
+
+static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
+{
+ extern DOM_SID global_sid_World;
+ fstring u_name;
+ fstring g_name;
+
+ /* "Everyone" always matches every uid. */
+
+ if (sid_equal(&group_ace->trustee, &global_sid_World))
+ return True;
+
+ fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
+ fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
+
+ /*
+ * Due to the winbind interfaces we need to do this via names,
+ * not uids/gids.
+ */
+
+ return user_in_group_list(u_name, g_name );
}
/****************************************************************************
@@ -537,24 +568,16 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
BOOL got_user = False;
BOOL got_grp = False;
BOOL got_other = False;
+ canon_ace *pace_other = NULL;
+ canon_ace *pace_group = NULL;
for (pace = *pp_ace; pace; pace = pace->next) {
if (pace->type == SMB_ACL_USER_OBJ) {
- if (setting_acl) {
- /* Ensure owner has read access. */
- pace->perms |= S_IRUSR;
- if (fsp->is_directory)
- pace->perms |= (S_IWUSR|S_IXUSR);
-
- /*
- * Ensure create mask/force create mode is respected on set.
- */
-
- pace->perms = apply_default_perms(fsp, pace->perms, S_IRUSR);
- }
-
+ if (setting_acl)
+ apply_default_perms(fsp, pace, S_IRUSR);
got_user = True;
+
} else if (pace->type == SMB_ACL_GROUP_OBJ) {
/*
@@ -562,8 +585,10 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
*/
if (setting_acl)
- pace->perms = apply_default_perms(fsp, pace->perms, S_IRGRP);
+ apply_default_perms(fsp, pace, S_IRGRP);
got_grp = True;
+ pace_group = pace;
+
} else if (pace->type == SMB_ACL_OTHER) {
/*
@@ -571,8 +596,9 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
*/
if (setting_acl)
- pace->perms = apply_default_perms(fsp, pace->perms, S_IROTH);
+ apply_default_perms(fsp, pace, S_IROTH);
got_other = True;
+ pace_other = pace;
}
}
@@ -587,9 +613,21 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->owner_type = UID_ACE;
pace->unix_ug.uid = pst->st_uid;
pace->trustee = *pfile_owner_sid;
- pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
pace->attr = ALLOW_ACE;
+ if (setting_acl) {
+ /* If we only got an "everyone" perm, just use that. */
+ if (!got_grp && got_other)
+ pace->perms = pace_other->perms;
+ else if (got_grp && uid_entry_in_group(pace, pace_group))
+ pace->perms = pace_group->perms;
+ else
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
+ apply_default_perms(fsp, pace, S_IRUSR);
+ } else {
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
+ }
+
DLIST_ADD(*pp_ace, pace);
}
@@ -604,8 +642,17 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->owner_type = GID_ACE;
pace->unix_ug.uid = pst->st_gid;
pace->trustee = *pfile_grp_sid;
- pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
pace->attr = ALLOW_ACE;
+ if (setting_acl) {
+ /* If we only got an "everyone" perm, just use that. */
+ if (got_other)
+ pace->perms = pace_other->perms;
+ else
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ apply_default_perms(fsp, pace, S_IRGRP);
+ } else {
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ }
DLIST_ADD(*pp_ace, pace);
}
@@ -621,8 +668,9 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->owner_type = WORLD_ACE;
pace->unix_ug.world = -1;
pace->trustee = global_sid_World;
- pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
pace->attr = ALLOW_ACE;
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
+ apply_default_perms(fsp, pace, S_IROTH);
DLIST_ADD(*pp_ace, pace);
}
@@ -932,33 +980,6 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
}
/****************************************************************************
- Check if a given uid/SID is in a group gid/SID. This is probably very
- expensive and will need optimisation. A *lot* of optimisation :-). JRA.
-****************************************************************************/
-
-static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
-{
- extern DOM_SID global_sid_World;
- fstring u_name;
- fstring g_name;
-
- /* "Everyone" always matches every uid. */
-
- if (sid_equal(&group_ace->trustee, &global_sid_World))
- return True;
-
- fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
- fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
-
- /*
- * Due to the winbind interfaces we need to do this via names,
- * not uids/gids.
- */
-
- return user_in_group_list(u_name, g_name );
-}
-
-/****************************************************************************
ASCII art time again... JRA :-).
We have 3 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
@@ -2026,28 +2047,28 @@ static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_
/* try the direct way first */
ret = vfs_chown(conn, fname, uid, gid);
- if (ret == 0) return 0;
+ if (ret == 0)
+ return 0;
if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
return -1;
- if (vfs_stat(conn,fname,&st)) {
+ if (vfs_stat(conn,fname,&st))
return -1;
- }
fsp = open_file_fchmod(conn,fname,&st);
- if (!fsp) {
+ if (!fsp)
return -1;
- }
/* only allow chown to the current user. This is more secure,
and also copes with the case where the SID in a take ownership ACL is
a local SID on the users workstation
*/
uid = current_user.uid;
-
+
become_root();
- ret = vfswrap_fchown(fsp, fsp->fd, uid, gid);
+ /* Keep the current file gid the same. */
+ ret = vfswrap_fchown(fsp, fsp->fd, uid, (gid_t)-1);
unbecome_root();
close_file_fchmod(fsp);
@@ -2099,7 +2120,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
* Unpack the user/group/world id's.
*/
- if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
+ if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd))
return False;
/*
@@ -2367,6 +2388,7 @@ BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
if (dir_acl != NULL && (conn->vfs_ops.sys_acl_get_entry(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
has_acl = True;
- conn->vfs_ops.sys_acl_free_acl(conn, dir_acl);
+ if (dir_acl)
+ conn->vfs_ops.sys_acl_free_acl(conn, dir_acl);
return has_acl;
}
diff --git a/source/smbd/process.c b/source/smbd/process.c
index e882853e6de..4eaa396f6b4 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -46,8 +46,8 @@ extern int last_message;
extern int global_oplock_break;
extern userdom_struct current_user_info;
extern int smb_read_error;
-extern VOLATILE sig_atomic_t reload_after_sighup;
-extern VOLATILE sig_atomic_t got_sig_term;
+SIG_ATOMIC_T reload_after_sighup;
+SIG_ATOMIC_T got_sig_term;
extern BOOL global_machine_password_needs_changing;
extern fstring global_myworkgroup;
extern pstring global_myname;
@@ -113,10 +113,12 @@ BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
oplock messages, change notify events etc.
****************************************************************************/
-static void async_processing(fd_set *fds, char *buffer, int buffer_len)
+static void async_processing(char *buffer, int buffer_len)
{
+ DEBUG(10,("async_processing: Doing async processing.\n"));
+
/* check for oplock messages (both UDP and kernel) */
- if (receive_local_message(fds, buffer, buffer_len, 0)) {
+ if (receive_local_message(buffer, buffer_len, 1)) {
process_local_message(buffer, buffer_len);
}
@@ -197,6 +199,27 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
*/
FD_ZERO(&fds);
+
+ /*
+ * Ensure we process oplock break messages by preference.
+ * We have to do this before the select, after the select
+ * and if the select returns EINTR. This is due to the fact
+ * that the selects called from async_processing can eat an EINTR
+ * caused by a signal (we can't take the break message there).
+ * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
+ */
+
+ if (oplock_message_waiting(&fds)) {
+ DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
+ async_processing(buffer, buffer_len);
+ /*
+ * After async processing we must go and do the select again, as
+ * the state of the flag in fds for the server file descriptor is
+ * indeterminate - we may have done I/O on it in the oplock processing. JRA.
+ */
+ goto again;
+ }
+
FD_SET(smbd_server_fd(),&fds);
maxfd = setup_oplock_select_set(&fds);
@@ -210,7 +233,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
is the best we can do until the oplock code knows more about
signals */
if (selrtn == -1 && errno == EINTR) {
- async_processing(&fds, buffer, buffer_len);
+ async_processing(buffer, buffer_len);
/*
* After async processing we must go and do the select again, as
* the state of the flag in fds for the server file descriptor is
@@ -240,7 +263,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
if (oplock_message_waiting(&fds)) {
DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
- async_processing(&fds, buffer, buffer_len);
+ async_processing(buffer, buffer_len);
/*
* After async processing we must go and do the select again, as
* the state of the flag in fds for the server file descriptor is
@@ -280,7 +303,6 @@ BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
void respond_to_all_remaining_local_messages(void)
{
char buffer[1024];
- fd_set fds;
/*
* Assert we have no exclusive open oplocks.
@@ -293,23 +315,12 @@ void respond_to_all_remaining_local_messages(void)
}
/*
- * Setup the select read fd set.
- */
-
- FD_ZERO(&fds);
- if(!setup_oplock_select_set(&fds))
- return;
-
- /*
* Keep doing receive_local_message with a 1 ms timeout until
* we have no more messages.
*/
- while(receive_local_message(&fds, buffer, sizeof(buffer), 1)) {
+ while(receive_local_message(buffer, sizeof(buffer), 1)) {
/* Deal with oplock break requests from other smbd's. */
process_local_message(buffer, sizeof(buffer));
-
- FD_ZERO(&fds);
- (void)setup_oplock_select_set(&fds);
}
return;
diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c
index 5e744bc97dd..4cfa05b1997 100644
--- a/source/smbd/quotas.c
+++ b/source/smbd/quotas.c
@@ -42,28 +42,15 @@ BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_B
#ifdef LINUX
#include <sys/types.h>
-#include <asm/types.h>
+#include <mntent.h>
/*
* This shouldn't be neccessary - it should be /usr/include/sys/quota.h
- * Unfortunately, RH7.1 ships with a different quota system using struct mem_dqblk
- * rather than the struct dqblk defined in /usr/include/sys/quota.h.
- * This means we must include linux/quota.h to have a hope of working on
- * RH7.1 systems. And it also means this breaks if the kernel is upgraded
- * to a Linus 2.4.x (where x > the minor number shipped with RH7.1) until
- * Linus synchronises with the AC patches. Sometimes I *hate* Linux :-). JRA.
+ * So we include all the files has *should* be in the system into a large,
+ * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
*/
-#include <linux/quota.h>
-#ifdef HAVE_LINUX_XQM_H
-#include <linux/xqm.h>
-#endif
-
-#include <mntent.h>
-#include <linux/unistd.h>
-
-
-#define LINUX_QUOTAS_2
+#include "samba_linux_quota.h"
typedef struct _LINUX_SMB_DISK_QUOTA {
SMB_BIG_UINT bsize;
@@ -82,7 +69,6 @@ typedef struct _LINUX_SMB_DISK_QUOTA {
static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
{
int ret = -1;
-#ifdef HAVE_LINUX_XQM_H
struct fs_disk_quota D;
ZERO_STRUCT(D);
@@ -96,7 +82,6 @@ static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QU
dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
dp->curinodes = (SMB_BIG_UINT)D.d_icount;
dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
-#endif
return ret;
}
@@ -104,23 +89,36 @@ static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QU
Abstract out the old and new Linux quota get calls.
****************************************************************************/
-static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
+static int get_smb_linux_v1_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
{
+ struct v1_kern_dqblk D;
int ret;
-#ifdef LINUX_QUOTAS_1
- struct dqblk D;
+
ZERO_STRUCT(D);
- dp->bsize = (SMB_BIG_UINT)1024;
-#else /* LINUX_QUOTAS_2 */
- struct mem_dqblk D;
+ dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
+ return -1;
+
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
+
+ return 0;
+}
+
+static int get_smb_linux_v2_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ struct v2_kern_dqblk D;
+ int ret;
+
ZERO_STRUCT(D);
-#ifndef QUOTABLOCK_SIZE
-#define QUOTABLOCK_SIZE 1024
-#endif
dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
-#endif
- if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
+ if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
return -1;
dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
@@ -128,18 +126,38 @@ static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QU
dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
-#ifdef LINUX_QUOTAS_1
- dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
-#else /* LINUX_QUOTAS_2 */
- dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace)/ dp->bsize;
-#endif
+ return 0;
+}
+
+/****************************************************************************
+ Brand-new generic quota interface.
+****************************************************************************/
+
+static int get_smb_linux_gen_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
+{
+ struct if_dqblk D;
+ int ret;
+
+ ZERO_STRUCT(D);
+ dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
+
+ if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
+ return -1;
+
+ dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
+ dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
+ dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
+ dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
+ dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
+ dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
return 0;
}
/****************************************************************************
-try to get the disk space from disk quotas (LINUX version)
+ Try to get the disk space from disk quotas (LINUX version).
****************************************************************************/
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
@@ -182,10 +200,18 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB
save_re_uid();
set_effective_uid(0);
- if (strcmp(mnt->mnt_type, "xfs") == 0)
+
+ if (strcmp(mnt->mnt_type, "xfs")) {
+ r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, &D);
+ if (r == -1) {
+ r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, &D);
+ if (r == -1)
+ r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, &D);
+ }
+ } else {
r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D);
- else
- r=get_smb_linux_vfs_quota(mnt->mnt_fsname, euser_id, &D);
+ }
+
restore_re_uid();
/* Use softlimit to determine disk space, except when it has been exceeded */
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 562b0492ca0..78294952c18 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -553,6 +553,15 @@ static int smb_delete_user(char *unix_user)
pstring del_script;
int ret;
+ /*
+ * Sanity check -- do not delete 'root' account
+ */
+
+ if (StrCaseCmp("root", unix_user) == 0) {
+ DEBUG(0,("smb_delete_user: Will not delete the [%s] user account!\n", unix_user));
+ return -1;
+ }
+
pstrcpy(del_script, lp_deluser_script());
if (! *del_script)
return -1;
@@ -2052,8 +2061,8 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
* Tine Smukavec <valentin.smukavec@hermes.si>.
*/
- if (!rc && is_mangled(mask))
- check_mangled_cache( mask );
+ if (!rc && mangle_is_mangled(mask))
+ mangle_check_cache( mask );
has_wild = ms_has_wild(mask);
@@ -3764,8 +3773,8 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO
* Tine Smukavec <valentin.smukavec@hermes.si>.
*/
- if (!rc && is_mangled(mask))
- check_mangled_cache( mask );
+ if (!rc && mangle_is_mangled(mask))
+ mangle_check_cache( mask );
has_wild = ms_has_wild(mask);
@@ -3776,7 +3785,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO
/*
* No wildcards - just process the one file.
*/
- BOOL is_short_name = is_8_3(name, True);
+ BOOL is_short_name = mangle_is_8_3(name, True);
/* Add a terminating '/' to the directory name. */
pstrcat(directory,"/");
@@ -3792,7 +3801,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO
}
DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
-directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
+directory = %s, newname = %s, newname_last_component = %s, mangle_is_8_3 = %d\n",
case_sensitive, case_preserve, short_case_preserve, directory,
newname, newname_last_component, is_short_name));
@@ -4173,8 +4182,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
* Tine Smukavec <valentin.smukavec@hermes.si>.
*/
- if (!rc && is_mangled(mask))
- check_mangled_cache( mask );
+ if (!rc && mangle_is_mangled(mask))
+ mangle_check_cache( mask );
has_wild = ms_has_wild(mask);
diff --git a/source/smbd/server.c b/source/smbd/server.c
index b18921e1af3..bfee036dc5a 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -64,7 +64,7 @@ void smbd_set_server_fd(int fd)
Terminate signal.
****************************************************************************/
-VOLATILE sig_atomic_t got_sig_term = 0;
+SIG_ATOMIC_T got_sig_term = 0;
static void sig_term(void)
{
@@ -76,7 +76,7 @@ static void sig_term(void)
Catch a sighup.
****************************************************************************/
-VOLATILE sig_atomic_t reload_after_sighup = 0;
+SIG_ATOMIC_T reload_after_sighup = 0;
static void sig_hup(int sig)
{
@@ -382,7 +382,7 @@ BOOL reload_services(BOOL test)
}
}
- reset_mangled_cache();
+ mangle_reset_cache();
reset_stat_cache();
/* this forces service parameters to be flushed */
diff --git a/source/smbd/service.c b/source/smbd/service.c
index 22aecdb4929..4d40d8dec1b 100644
--- a/source/smbd/service.c
+++ b/source/smbd/service.c
@@ -41,7 +41,6 @@ extern fstring remote_machine;
BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
{
- extern char magic_char;
static connection_struct *last_conn;
int snum;
@@ -72,7 +71,6 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
short_case_preserve = lp_shortpreservecase(snum);
case_mangle = lp_casemangle(snum);
case_sensitive = lp_casesensitive(snum);
- magic_char = lp_magicchar(snum);
use_mangled_map = (*lp_mangled_map(snum) ? True:False);
return(True);
}
@@ -227,7 +225,9 @@ connection_struct *make_connection(char *service,char *user,char *password, int
BOOL guest = False;
BOOL force = False;
connection_struct *conn;
+#if !CHECK_PATH_ON_TCONX
struct stat st;
+#endif
uid_t euid;
int ret;
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 9af0b0ddb58..5e74845f4ef 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -399,7 +399,7 @@ static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *ps
ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
#endif
#ifdef S_ISUID
- ret |= ((perms & UNIX_SET_UID ) ? S_ISVTX : 0);
+ ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
#endif
if (VALID_STAT(*pst) && S_ISDIR(pst->st_mode)) {
@@ -417,6 +417,21 @@ 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(1,("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.
****************************************************************************/
@@ -490,7 +505,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive)))
got_match = mask_match(fname, mask, case_sensitive);
- if(!got_match && !is_8_3(fname, False)) {
+ if(!got_match && !mangle_is_8_3(fname, False)) {
/*
* It turns out that NT matches wildcards against
@@ -501,7 +516,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
pstring newname;
pstrcpy( newname, fname);
- name_map_mangle( newname, True, False, SNUM(conn));
+ mangle_map( newname, True, False, SNUM(conn));
if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive)))
got_match = mask_match(newname, mask, case_sensitive);
}
@@ -571,7 +586,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
}
}
- name_map_mangle(fname,False,True,SNUM(conn));
+ mangle_map(fname,False,True,SNUM(conn));
p = pdata;
nameptr = p;
@@ -648,7 +663,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
break;
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- was_8_3 = is_8_3(fname, True);
+ was_8_3 = mangle_is_8_3(fname, True);
len = 94+strlen(fname);
len = (len + 3) & ~3;
SIVAL(p,0,len); p += 4;
@@ -665,8 +680,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
SIVAL(p,0,0); p += 4;
if (!was_8_3) {
fstrcpy(p+2,fname);
- if(!name_map_mangle(p+2,True,True,SNUM(conn)))
- (p+2)[12] = 0;
+ mangle_map(p+2,True,True,SNUM(conn));
strupper(p+2);
SSVAL(p, 0, strlen(p+2));
} else {
@@ -1031,8 +1045,8 @@ close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
* (see PR#13758). JRA.
*/
- if(!is_8_3( mask, False))
- name_map_mangle(mask, True, True, SNUM(conn));
+ if(!mangle_is_8_3_wildcards( mask, False))
+ mangle_map(mask, True, True, SNUM(conn));
return(-1);
}
@@ -1194,7 +1208,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
*/
if(dname != NULL)
- name_map_mangle( dname, False, True, SNUM(conn));
+ mangle_map( dname, False, True, SNUM(conn));
if(dname && strcsequal( resume_name, dname)) {
SeekDir(dirptr, current_pos+1);
@@ -1220,7 +1234,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
*/
if(dname != NULL)
- name_map_mangle( dname, False, True, SNUM(conn));
+ mangle_map( dname, False, True, SNUM(conn));
if(dname && strcsequal( resume_name, dname)) {
SeekDir(dirptr, current_pos+1);
@@ -1424,6 +1438,12 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
SMB_BIG_UINT dfree,dsize,bsize,secs_per_unit;;
data_len = 24;
conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
+ if (bsize < 1024) {
+ SMB_BIG_UINT factor = 1024/bsize;
+ bsize = 1024;
+ dsize /= factor;
+ dfree /= factor;
+ }
secs_per_unit = 2;
SBIG_UINT(pdata,0,dsize*(bsize/(512*secs_per_unit)));
SBIG_UINT(pdata,8,dfree*(bsize/(512*secs_per_unit)));
@@ -1437,11 +1457,11 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
SMB_BIG_UINT dfree,dsize,bsize;
data_len = 32;
conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
- SBIG_UINT(pdata,0,dsize);
- SBIG_UINT(pdata,8,dsize);
- SBIG_UINT(pdata,16,dfree);
- SIVAL(pdata,24,bsize/512);
- SIVAL(pdata,28,512);
+ SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
+ SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
+ SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
+ SIVAL(pdata,24,bsize/512); /* Sectors per allocation unit. */
+ SIVAL(pdata,28,512); /* Bytes per sector. */
break;
}
@@ -1795,9 +1815,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
pstring short_name;
pstrcpy(short_name,p);
/* Mangle if not already 8.3 */
- if(!is_8_3(short_name, True)) {
- if(!name_map_mangle(short_name,True,True,SNUM(conn)))
- *short_name = '\0';
+ if(!mangle_is_8_3(short_name, True)) {
+ mangle_map(short_name,True,True,SNUM(conn));
}
strupper(short_name);
SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
@@ -2355,10 +2374,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
SSVAL(params,0,0);
- if (fsp) {
+ if (fsp) {
/* the pending modtime overrides the current modtime */
sbuf.st_mtime = fsp->pending_modtime;
- }
+ }
size = sbuf.st_size;
tvs.modtime = sbuf.st_mtime;
@@ -2369,12 +2388,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
set_owner = VALID_STAT(sbuf) ? sbuf.st_uid : (uid_t)SMB_UID_NO_CHANGE;
set_grp = VALID_STAT(sbuf) ? sbuf.st_gid : (gid_t)SMB_GID_NO_CHANGE;
- if (total_data > 4 && IVAL(pdata,0) == total_data) {
- /* uggh, EAs for OS2 */
- DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
- return ERROR_DOS(ERRDOS,ERReasnotsupported);
- }
-
switch (info_level) {
case SMB_INFO_STANDARD:
case SMB_INFO_QUERY_EA_SIZE:
@@ -2575,16 +2588,19 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
if (total_data < 100)
return(ERROR_DOS(ERRDOS,ERRinvalidparam));
- size=IVAL(pdata,0); /* first 8 Bytes are size */
+ if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
+ IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
+ size=IVAL(pdata,0); /* first 8 Bytes are size */
#ifdef LARGE_SMB_OFF_T
- size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
+ size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
#else /* LARGE_SMB_OFF_T */
- if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return ERROR_DOS(ERRDOS,ERRunknownlevel);
+ if (IVAL(pdata,4) != 0) /* more than 32 bits? */
+ return ERROR_DOS(ERRDOS,ERRunknownlevel);
#endif /* LARGE_SMB_OFF_T */
+ }
pdata+=24; /* ctime & st_blocks are not changed */
- tvs.actime = interpret_long_date(pdata); /* access_time */
- tvs.modtime = interpret_long_date(pdata+8); /* modification_time */
+ tvs.actime = interpret_long_unix_date(pdata); /* access_time */
+ tvs.modtime = interpret_long_unix_date(pdata+8); /* modification_time */
pdata+=16;
set_owner = (uid_t)IVAL(pdata,0);
pdata += 8;
@@ -2656,7 +2672,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
if (raw_unixmode != SMB_MODE_NO_CHANGE) {
DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n",
- unixmode, fname ));
+ (unsigned int)unixmode, fname ));
if (vfs_chmod(conn,fname,unixmode) != 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
diff --git a/source/smbd/uid.c b/source/smbd/uid.c
index 89d89b33c36..b94fc05875d 100644
--- a/source/smbd/uid.c
+++ b/source/smbd/uid.c
@@ -114,8 +114,10 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid)
return(True);
} else if ((current_user.conn == conn) &&
(vuser != 0) && (current_user.vuid == vuid) &&
- (current_user.uid == vuser->uid)) {
+ (current_user.uid == vuser->uid))
+ {
DEBUG(4,("change_to_user: Skipping user change - already user\n"));
+ return True;
}
snum = SNUM(conn);
diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c
index 4545671de94..2d7cf05bf9b 100644
--- a/source/smbd/vfs-wrap.c
+++ b/source/smbd/vfs-wrap.c
@@ -409,6 +409,7 @@ int vfswrap_chown(connection_struct *conn, const char *path, uid_t uid, gid_t gi
int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid)
{
+#ifdef HAVE_FCHOWN
int result;
START_PROFILE(syscall_fchown);
@@ -416,6 +417,10 @@ int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid)
result = fchown(fd, uid, gid);
END_PROFILE(syscall_fchown);
return result;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
}
int vfswrap_chdir(connection_struct *conn, const char *path)