From 1c2aacd6da923efbc0b87e720399417f008f82c2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 29 Feb 2012 16:05:50 -0800 Subject: Add open_dir_with_privilege() to ensure we're opening the correct directory when doing backup requests. Autobuild-User: Jeremy Allison Autobuild-Date: Thu Mar 1 03:50:40 CET 2012 on sn-devel-104 --- source3/smbd/dir.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++-- source3/smbd/proto.h | 4 ++- source3/smbd/reply.c | 1 + source3/smbd/smb2_find.c | 1 + source3/smbd/trans2.c | 1 + 5 files changed, 72 insertions(+), 3 deletions(-) diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index c1a850ed32..103dbc8a33 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -412,6 +412,60 @@ static void dptr_close_oldest(struct smbd_server_connection *sconn, } } +/**************************************************************************** + Safely do an OpenDir as root, ensuring we're in the right place. +****************************************************************************/ + +static struct smb_Dir *open_dir_with_privilege(connection_struct *conn, + struct smb_request *req, + const char *path, + const char *wcard, + uint32_t attr) +{ + NTSTATUS status; + struct smb_Dir *dir_hnd = NULL; + struct smb_filename *smb_fname_cwd = NULL; + char *saved_dir = vfs_GetWd(talloc_tos(), conn); + struct privilege_paths *priv_paths = req->priv_paths; + int ret; + + if (saved_dir == NULL) { + return NULL; + } + + if (vfs_ChDir(conn, path) == -1) { + return NULL; + } + + /* Now check the stat value is the same. */ + status = create_synthetic_smb_fname(talloc_tos(), ".", + NULL, NULL, + &smb_fname_cwd); + + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + ret = SMB_VFS_STAT(conn, smb_fname_cwd); + if (ret != 0) { + goto out; + } + + if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) { + DEBUG(0,("open_dir_with_privilege: stat mismatch between %s " + "and %s\n", + path, + smb_fname_str_dbg(&priv_paths->parent_name))); + goto out; + } + + dir_hnd = OpenDir(NULL, conn, ".", wcard, attr); + + out: + + vfs_ChDir(conn, saved_dir); + return dir_hnd; +} + /**************************************************************************** Create a new dir ptr. If the flag old_handle is true then we must allocate from the bitmap range 0 - 255 as old SMBsearch directory handles are only @@ -421,7 +475,9 @@ static void dptr_close_oldest(struct smbd_server_connection *sconn, wcard must not be zero. ****************************************************************************/ -NTSTATUS dptr_create(connection_struct *conn, files_struct *fsp, +NTSTATUS dptr_create(connection_struct *conn, + struct smb_request *req, + files_struct *fsp, const char *path, bool old_handle, bool expect_close,uint16 spid, const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret) { @@ -480,7 +536,15 @@ NTSTATUS dptr_create(connection_struct *conn, files_struct *fsp, if (!NT_STATUS_IS_OK(status)) { return status; } - dir_hnd = OpenDir(NULL, conn, path, wcard, attr); + if (req && req->priv_paths) { + dir_hnd = open_dir_with_privilege(conn, + req, + path, + wcard, + attr); + } else { + dir_hnd = OpenDir(NULL, conn, path, wcard, attr); + } } if (!dir_hnd) { diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 9a1e9cd683..599180084e 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -197,7 +197,9 @@ void dptr_closecnum(connection_struct *conn); void dptr_idlecnum(connection_struct *conn); void dptr_closepath(struct smbd_server_connection *sconn, char *path,uint16 spid); -NTSTATUS dptr_create(connection_struct *conn, files_struct *fsp, +NTSTATUS dptr_create(connection_struct *conn, + struct smb_request *req, + files_struct *fsp, const char *path, bool old_handle, bool expect_close,uint16 spid, const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret); void dptr_CloseDir(files_struct *fsp); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index eebd77d3ef..0ab764c2d4 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -1497,6 +1497,7 @@ void reply_search(struct smb_request *req) SCVAL(status,0,(dirtype & 0x1F)); nt_status = dptr_create(conn, + NULL, /* req */ NULL, /* fsp */ directory, True, diff --git a/source3/smbd/smb2_find.c b/source3/smbd/smb2_find.c index 7c19d7538a..99d3447860 100644 --- a/source3/smbd/smb2_find.c +++ b/source3/smbd/smb2_find.c @@ -322,6 +322,7 @@ static struct tevent_req *smbd_smb2_find_send(TALLOC_CTX *mem_ctx, wcard_has_wild = ms_has_wild(in_file_name); status = dptr_create(conn, + NULL, /* req */ fsp, fsp->fsp_name->base_name, false, /* old_handle */ diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 21f31f17b3..24642cd818 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -2468,6 +2468,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd needed as lanman2 assumes these are being saved between calls */ ntstatus = dptr_create(conn, + req, NULL, /* fsp */ directory, False, -- cgit