diff options
author | Gerald Carter <jerry@samba.org> | 2002-06-17 18:36:36 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2002-06-17 18:36:36 +0000 |
commit | 1e6e5b299c235b513095a76a4cd9fffc41e8fc9c (patch) | |
tree | 9f741529073ad411cc7328334e26d3e35b1d33f1 /source/smbd | |
parent | a11c5d7ad07d259d764aede4745d13f8163a8212 (diff) | |
download | samba-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.c | 8 | ||||
-rw-r--r-- | source/smbd/dfree.c | 9 | ||||
-rw-r--r-- | source/smbd/dir.c | 154 | ||||
-rw-r--r-- | source/smbd/filename.c | 786 | ||||
-rw-r--r-- | source/smbd/mangle.c | 1075 | ||||
-rw-r--r-- | source/smbd/mangle_hash.c | 935 | ||||
-rw-r--r-- | source/smbd/mangle_hash2.c | 24 | ||||
-rw-r--r-- | source/smbd/mangle_map.c | 2 | ||||
-rw-r--r-- | source/smbd/notify_kernel.c | 98 | ||||
-rw-r--r-- | source/smbd/nttrans.c | 11 | ||||
-rw-r--r-- | source/smbd/open.c | 4 | ||||
-rw-r--r-- | source/smbd/oplock.c | 75 | ||||
-rw-r--r-- | source/smbd/oplock_irix.c | 18 | ||||
-rw-r--r-- | source/smbd/oplock_linux.c | 57 | ||||
-rw-r--r-- | source/smbd/posix_acls.c | 170 | ||||
-rw-r--r-- | source/smbd/process.c | 49 | ||||
-rw-r--r-- | source/smbd/quotas.c | 104 | ||||
-rw-r--r-- | source/smbd/reply.c | 25 | ||||
-rw-r--r-- | source/smbd/server.c | 6 | ||||
-rw-r--r-- | source/smbd/service.c | 4 | ||||
-rw-r--r-- | source/smbd/trans2.c | 84 | ||||
-rw-r--r-- | source/smbd/uid.c | 4 | ||||
-rw-r--r-- | source/smbd/vfs-wrap.c | 5 |
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) |