summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2009-02-04 16:33:52 -0800
committerJeremy Allison <jra@samba.org>2009-02-04 16:33:52 -0800
commite7c09d8b105d8182e7ae3948a664169dc13198e9 (patch)
tree51c4abdd43cf4331e180c8ffbd5a4861daa4ee4d
parentef098bd621b544a651636db4b7d6cdd777c83d18 (diff)
downloadsamba-e7c09d8b105d8182e7ae3948a664169dc13198e9.tar.gz
samba-e7c09d8b105d8182e7ae3948a664169dc13198e9.tar.bz2
samba-e7c09d8b105d8182e7ae3948a664169dc13198e9.zip
Fix bug #Bug 6090 renaming or deleting a "not matching/resolving" symlink is failing.
Reported by Kukks. Make sure we correctly use LSTAT in all cases where POSIX pathnames are being used. This matters when dealing with symlinks pointing to invalid paths being renamed or deleted not all deletes and renames are done via an nt_create open. Jeremy.
-rw-r--r--source3/smbd/filename.c30
-rw-r--r--source3/smbd/open.c54
-rw-r--r--source3/smbd/reply.c34
3 files changed, 88 insertions, 30 deletions
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index d240ecfa64..003cb0ffd4 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -126,7 +126,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
char *stream = NULL;
bool component_was_mangled = False;
bool name_has_wildcard = False;
+ bool posix_pathnames = false;
NTSTATUS result;
+ int ret = -1;
SET_STAT_INVALID(*pst);
*pp_conv_path = NULL;
@@ -225,7 +227,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
}
}
- if (!lp_posix_pathnames()) {
+ posix_pathnames = lp_posix_pathnames();
+
+ if (!posix_pathnames) {
stream = strchr_m(name, ':');
if (stream != NULL) {
@@ -268,7 +272,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
* stat the name - if it exists then we are all done!
*/
- if (SMB_VFS_STAT(conn,name,&st) == 0) {
+ if (posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn,name,&st);
+ } else {
+ ret = SMB_VFS_STAT(conn,name,&st);
+ }
+
+ if (ret == 0) {
/* Ensure we catch all names with in "/."
this is disallowed under Windows. */
const char *p = strstr(name, "/."); /* mb safe. */
@@ -380,7 +390,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
* Check if the name exists up to this point.
*/
- if (SMB_VFS_STAT(conn,name, &st) == 0) {
+ if (posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn,name, &st);
+ } else {
+ ret = SMB_VFS_STAT(conn,name, &st);
+ }
+
+ if (ret == 0) {
/*
* It exists. it must either be a directory or this must
* be the last part of the path for it to be OK.
@@ -598,7 +614,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
* if it exists. JRA.
*/
- if (SMB_VFS_STAT(conn,name, &st) == 0) {
+ if (posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn,name, &st);
+ } else {
+ ret = SMB_VFS_STAT(conn,name, &st);
+ }
+
+ if (ret == 0) {
*pst = st;
} else {
SET_STAT_INVALID(st);
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index bc5107447f..f7a52d7bd2 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -432,28 +432,42 @@ static NTSTATUS open_file(files_struct *fsp,
access_mask,
&access_granted);
if (!NT_STATUS_IS_OK(status)) {
-
- /* Were we trying to do a stat open
- * for delete and didn't get DELETE
- * access (only) ? Check if the
- * directory allows DELETE_CHILD.
- * See here:
- * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
- * for details. */
-
- if (!(NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
- (access_mask & DELETE_ACCESS) &&
- (access_granted == DELETE_ACCESS) &&
- can_delete_file_in_directory(conn, path))) {
- DEBUG(10, ("open_file: Access denied on "
- "file %s\n",
- path));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ if ((access_mask & DELETE_ACCESS) &&
+ (access_granted == DELETE_ACCESS) &&
+ can_delete_file_in_directory(conn, path)) {
+ /* Were we trying to do a stat open
+ * for delete and didn't get DELETE
+ * access (only) ? Check if the
+ * directory allows DELETE_CHILD.
+ * See here:
+ * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
+ * for details. */
+
+ DEBUG(10,("open_file: overrode ACCESS_DENIED "
+ "on file %s\n",
+ path ));
+ } else {
+ DEBUG(10, ("open_file: Access denied on "
+ "file %s\n",
+ path));
+ return status;
+ }
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
+ fsp->posix_open &&
+ S_ISLNK(psbuf->st_mode)) {
+ /* This is a POSIX stat open for delete
+ * or rename on a symlink that points
+ * nowhere. Allow. */
+ DEBUG(10, ("open_file: allowing POSIX open "
+ "on bad symlink %s\n",
+ path ));
+ } else {
+ DEBUG(10, ("open_file: check_open_rights "
+ "on file %s returned %s\n",
+ path, nt_errstr(status) ));
return status;
}
-
- DEBUG(10,("open_file: overrode ACCESS_DENIED "
- "on file %s\n",
- path ));
}
}
}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index f2d4ff78a7..bb5fadd465 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -5616,7 +5616,13 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
return map_nt_error_from_unix(errno);
}
} else {
- if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
+ int ret = -1;
+ if (fsp->posix_open) {
+ ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf);
+ } else {
+ ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf);
+ }
+ if (ret == -1) {
return map_nt_error_from_unix(errno);
}
}
@@ -5721,6 +5727,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
const char *dname;
long offset = 0;
int create_options = 0;
+ bool posix_pathnames = lp_posix_pathnames();
ZERO_STRUCT(sbuf1);
ZERO_STRUCT(sbuf2);
@@ -5832,7 +5839,11 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
}
ZERO_STRUCT(sbuf1);
- SMB_VFS_STAT(conn, directory, &sbuf1);
+ if (posix_pathnames) {
+ SMB_VFS_LSTAT(conn, directory, &sbuf1);
+ } else {
+ SMB_VFS_STAT(conn, directory, &sbuf1);
+ }
if (S_ISDIR(sbuf1.st_mode)) {
create_options |= FILE_DIRECTORY_FILE;
@@ -5849,7 +5860,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
FILE_SHARE_WRITE),
FILE_OPEN, /* create_disposition*/
create_options, /* create_options */
- 0, /* file_attributes */
+ posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
0, /* oplock_request */
0, /* allocation_size */
NULL, /* sd */
@@ -5948,7 +5959,11 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
}
ZERO_STRUCT(sbuf1);
- SMB_VFS_STAT(conn, fname, &sbuf1);
+ if (posix_pathnames) {
+ SMB_VFS_LSTAT(conn, fname, &sbuf1);
+ } else {
+ SMB_VFS_STAT(conn, fname, &sbuf1);
+ }
create_options = 0;
@@ -5967,7 +5982,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
FILE_SHARE_WRITE),
FILE_OPEN, /* create_disposition*/
create_options, /* create_options */
- 0, /* file_attributes */
+ posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */
0, /* oplock_request */
0, /* allocation_size */
NULL, /* sd */
@@ -7167,7 +7182,14 @@ void reply_setattrE(struct smb_request *req)
return;
}
} else {
- if (SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf) == -1) {
+ int ret = -1;
+
+ if (fsp->posix_open) {
+ ret = SMB_VFS_LSTAT(conn, fsp->fsp_name, &sbuf);
+ } else {
+ ret = SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf);
+ }
+ if (ret == -1) {
status = map_nt_error_from_unix(errno);
reply_nterror(req, status);
END_PROFILE(SMBsetattrE);