diff --git a/source/smbd/dir.c b/source/smbd/dir.c index ca6f8bf..0248ad3 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -595,6 +595,7 @@ const char *dptr_ReadDirName(TALLOC_CTX *ctx, if (!dptr->did_stat) { char *pathreal = NULL; + ino_t ino = 0; /* We know the stored wcard contains no wildcard characters. See if we can match with a stat call. If we can't, then set did_stat to true to @@ -626,11 +627,17 @@ const char *dptr_ReadDirName(TALLOC_CTX *ctx, return NULL; } - if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) { + if (SMB_VFS_LSTAT(dptr->conn,pathreal,pst) == 0) + ino = pst->st_ino; + if (ino && (!S_ISLNK(pst->st_mode) || SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0)) { /* We need to set the underlying dir_hnd offset to -1 also as this function is usually called with the output from TellDir. */ dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET; TALLOC_FREE(pathreal); + /* Use symlink's inode number so that no two distinct files + have the same file id. */ + if (ino) + pst->st_ino = ino; return dptr->wcard; } else { /* If we get any other error than ENOENT or ENOTDIR diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index fb84522..7896e71 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -1355,25 +1355,39 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, TALLOC_FREE(pathreal); continue; } - } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) { - /* Needed to show the msdfs symlinks as - * directories */ - - if(lp_host_msdfs() && - lp_msdfs_root(SNUM(conn)) && - ((ms_dfs_link = is_msdfs_link(conn, pathreal, &sbuf)) == True)) { - DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s " - "as a directory\n", - pathreal)); - sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; - - } else { - - DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", + } else if (!VALID_STAT(sbuf)) { + if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) { + DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n", pathreal,strerror(errno))); TALLOC_FREE(pathreal); continue; } + if (S_ISLNK(sbuf.st_mode)) { + /* Use symlink's inode number so that no two distinct files + * have the same file id. */ + ino_t ino = sbuf.st_ino; + if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) { + /* Needed to show the msdfs symlinks as + * directories */ + + if(lp_host_msdfs() && + lp_msdfs_root(SNUM(conn)) && + ((ms_dfs_link = is_msdfs_link(conn, pathreal, &sbuf)) == True)) { + DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s " + "as a directory\n", + pathreal)); + sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR; + + } else { + + DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n", + pathreal,strerror(errno))); + TALLOC_FREE(pathreal); + continue; + } + } + sbuf.st_ino = ino; + } } if (ms_dfs_link) { @@ -3846,17 +3860,21 @@ static void call_trans2qfilepathinfo(connection_struct *conn, * to do this call. JRA. */ - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); - reply_unixerror(req,ERRDOS,ERRbadpath); + if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + if (!INFO_LEVEL_IS_UNIX(info_level) && S_ISLNK (sbuf.st_mode)) { + /* Use symlink's inode number so that no two distinct files + * have the same file id. */ + ino_t ino = sbuf.st_ino; + if (SMB_VFS_STAT(conn,fname,&sbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadpath); return; } - } else if (SMB_VFS_STAT(conn,fname,&sbuf)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; + sbuf.st_ino = ino; } fileid = vfs_file_id_from_sbuf(conn, &sbuf); @@ -3940,10 +3958,26 @@ static void call_trans2qfilepathinfo(connection_struct *conn, reply_unixerror(req, ERRDOS, ERRbadpath); return; } - } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf) && (info_level != SMB_INFO_IS_NAME_VALID)) { - DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; + } else if (!VALID_STAT(sbuf)) { + if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { + if (info_level != SMB_INFO_IS_NAME_VALID) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadpath); + return; + } + } else if (S_ISLNK(sbuf.st_mode)) { + /* Use symlink's inode number so that no two distinct files + * have the same file id. */ + ino_t ino = sbuf.st_ino; + if (SMB_VFS_STAT(conn,fname,&sbuf)) { + if ((info_level != SMB_INFO_IS_NAME_VALID)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); + reply_unixerror(req, ERRDOS, ERRbadpath); + return; + } + } else + sbuf.st_ino = ino; + } } fileid = vfs_file_id_from_sbuf(conn, &sbuf);