diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/filename.c | 175 | ||||
-rw-r--r-- | source3/smbd/msdfs.c | 15 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 90 | ||||
-rw-r--r-- | source3/smbd/open.c | 15 | ||||
-rw-r--r-- | source3/smbd/reply.c | 488 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 128 |
6 files changed, 537 insertions, 374 deletions
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 0d5529b6b0..36503483a8 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -29,10 +29,7 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *orig_path, - const char *basepath, - const char *streamname, - SMB_STRUCT_STAT *pst, - char **path); + struct smb_filename *smb_fname); /**************************************************************************** Mangle the 2nd name and check if it is then equal to the first name. @@ -83,10 +80,27 @@ static NTSTATUS determine_path_error(const char *name, } } +NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname, + char **full_name) +{ + if (smb_fname->stream_name) { + *full_name = talloc_asprintf(ctx, "%s%s", smb_fname->base_name, + smb_fname->stream_name); + } else { + *full_name = talloc_strdup(ctx, smb_fname->base_name); + } + + if (!*full_name) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + /**************************************************************************** This routine is called to convert names from the dos namespace to unix -namespace. It needs to handle any case conversions, mangling, format -changes etc. +namespace. It needs to handle any case conversions, mangling, format changes, +streams etc. We assume that we have already done a chdir() to the right "root" directory for this service. @@ -94,32 +108,34 @@ for this service. The function will return an NTSTATUS error if some part of the name except for the last part cannot be resolved, else NT_STATUS_OK. -Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't -get any fatal errors that should immediately terminate the calling -SMB processing whilst resolving. +Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we +didn't get any fatal errors that should immediately terminate the calling SMB +processing whilst resolving. -If the saved_last_component != 0, then the unmodified last component -of the pathname is returned there. If saved_last_component == 0 then nothing -is returned there. +If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component +of the pathname is set in smb_filename->original_lcomp. -If last_component_wcard is true then a MS wildcard was detected and +If UCF_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected and should be allowed in the last component of the path only. -On exit from unix_convert, if *pst was not null, then the file stat -struct will be returned if the file exists and was found, if not this -stat struct will be filled with zeros (and this can be detected by checking -for nlinks = 0, which can never be true for any file). +If the orig_path was a stream, smb_filename->base_name will point to the base +filename, and smb_filename->stream_name will point to the stream name. If +orig_path was not a stream, then smb_filename->stream_name will be NULL. + +On exit from unix_convert, the smb_filename->st stat struct will be populated +if the file exists and was found, if not this stat struct will be filled with +zeros (and this can be detected by checking for nlinks = 0, which can never be +true for any file). ****************************************************************************/ NTSTATUS unix_convert(TALLOC_CTX *ctx, - connection_struct *conn, - const char *orig_path, - bool allow_wcard_last_component, - char **pp_conv_path, - char **pp_saved_last_component, - SMB_STRUCT_STAT *pst) + connection_struct *conn, + const char *orig_path, + struct smb_filename **smb_fname_out, + uint32_t ucf_flags) { SMB_STRUCT_STAT st; + struct smb_filename *smb_fname = NULL; char *start, *end; char *dirpath = NULL; char *name = NULL; @@ -127,21 +143,26 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, bool component_was_mangled = False; bool name_has_wildcard = False; bool posix_pathnames = false; + bool allow_wcard_last_component = ucf_flags & UCF_ALLOW_WCARD_LCOMP; + bool save_last_component = ucf_flags & UCF_SAVE_LCOMP; NTSTATUS result; int ret = -1; - SET_STAT_INVALID(*pst); - *pp_conv_path = NULL; - if(pp_saved_last_component) { - *pp_saved_last_component = NULL; + *smb_fname_out = NULL; + + smb_fname = TALLOC_ZERO_P(talloc_tos(), struct smb_filename); + if (smb_fname == NULL) { + return NT_STATUS_NO_MEMORY; } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ - if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) { + if (!(smb_fname->base_name = talloc_strdup(smb_fname, + orig_path))) { return NT_STATUS_NO_MEMORY; } + *smb_fname_out = smb_fname; return NT_STATUS_OK; } @@ -174,7 +195,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, return NT_STATUS_NO_MEMORY; } if (SMB_VFS_STAT(conn,name,&st) == 0) { - *pst = st; + smb_fname->st = st; } else { return map_nt_error_from_unix(errno); } @@ -217,18 +238,20 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * Ensure saved_last_component is valid even if file exists. */ - if(pp_saved_last_component) { + if(save_last_component) { end = strrchr_m(name, '/'); if (end) { - *pp_saved_last_component = talloc_strdup(ctx, end + 1); + smb_fname->original_lcomp = talloc_strdup(ctx, + end + 1); } else { - *pp_saved_last_component = talloc_strdup(ctx, - name); + smb_fname->original_lcomp = talloc_strdup(ctx, name); } } posix_pathnames = lp_posix_pathnames(); + /* Strip off the stream. Should we use any of the other stream parsing + * at this point? Also, should we set the is_stream bit? */ if (!posix_pathnames) { stream = strchr_m(name, ':'); @@ -253,7 +276,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && stat_cache_lookup(conn, &name, &dirpath, &start, &st)) { - *pst = st; + smb_fname->st = st; goto done; } @@ -295,7 +318,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } stat_cache_add(orig_path, name, conn->case_sensitive); DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); - *pst = st; + smb_fname->st = st; goto done; } @@ -346,11 +369,11 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, *end = 0; } - if (pp_saved_last_component) { - TALLOC_FREE(*pp_saved_last_component); - *pp_saved_last_component = talloc_strdup(ctx, + if (save_last_component) { + TALLOC_FREE(smb_fname->original_lcomp); + smb_fname->original_lcomp = talloc_strdup(ctx, end ? end + 1 : start); - if (!*pp_saved_last_component) { + if (!smb_fname->original_lcomp) { DEBUG(0, ("talloc failed\n")); return NT_STATUS_NO_MEMORY; } @@ -427,7 +450,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * struct. JRA. */ - *pst = st; + smb_fname->st = st; } } else { @@ -621,7 +644,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } if (ret == 0) { - *pst = st; + smb_fname->st = st; } else { SET_STAT_INVALID(st); } @@ -703,35 +726,34 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); done: + smb_fname->base_name = name; + if (stream != NULL) { - char *tmp = NULL; + smb_fname->stream_name = stream; - result = build_stream_path(ctx, conn, orig_path, name, stream, - pst, &tmp); + /* Check path now that the base_name has been converted. */ + result = build_stream_path(ctx, conn, orig_path, smb_fname); if (!NT_STATUS_IS_OK(result)) { goto fail; } - - DEBUG(10, ("build_stream_path returned %s\n", tmp)); - - TALLOC_FREE(name); - name = tmp; } - *pp_conv_path = name; TALLOC_FREE(dirpath); + *smb_fname_out = smb_fname; return NT_STATUS_OK; fail: DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start)); if (*dirpath != '\0') { - *pp_conv_path = talloc_asprintf(ctx, - "%s/%s", dirpath, start); + smb_fname->base_name = talloc_asprintf(ctx, "%s/%s", dirpath, + start); } else { - *pp_conv_path = talloc_strdup(ctx, start); + smb_fname->base_name = talloc_strdup(ctx, start); } - if (!*pp_conv_path) { + if (!smb_fname->base_name) { DEBUG(0, ("talloc_asprintf failed\n")); return NT_STATUS_NO_MEMORY; } + + *smb_fname_out = smb_fname; TALLOC_FREE(name); TALLOC_FREE(dirpath); return result; @@ -923,25 +945,19 @@ int get_real_filename(connection_struct *conn, const char *path, static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *orig_path, - const char *basepath, - const char *streamname, - SMB_STRUCT_STAT *pst, - char **path) + struct smb_filename *smb_fname) { - SMB_STRUCT_STAT st; char *result = NULL; NTSTATUS status; unsigned int i, num_streams; struct stream_struct *streams = NULL; - result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname); - if (result == NULL) { + status = get_full_smb_filename(mem_ctx, smb_fname, &result); + if (!NT_STATUS_IS_OK(status)) { return NT_STATUS_NO_MEMORY; } - if (SMB_VFS_STAT(conn, result, &st) == 0) { - *pst = st; - *path = result; + if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) { return NT_STATUS_OK; } @@ -951,12 +967,12 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, goto fail; } - status = SMB_VFS_STREAMINFO(conn, NULL, basepath, mem_ctx, + /* Fall back to a case-insensitive scan of all streams on the file. */ + status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, mem_ctx, &num_streams, &streams); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { - SET_STAT_INVALID(*pst); - *path = result; + SET_STAT_INVALID(smb_fname->st); return NT_STATUS_OK; } @@ -967,8 +983,8 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, for (i=0; i<num_streams; i++) { DEBUG(10, ("comparing [%s] and [%s]: ", - streamname, streams[i].name)); - if (fname_equal(streamname, streams[i].name, + smb_fname->stream_name, streams[i].name)); + if (fname_equal(smb_fname->stream_name, streams[i].name, conn->case_sensitive)) { DEBUGADD(10, ("equal\n")); break; @@ -976,28 +992,33 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, DEBUGADD(10, ("not equal\n")); } + /* Couldn't find the stream. */ if (i == num_streams) { - SET_STAT_INVALID(*pst); - *path = result; + SET_STAT_INVALID(smb_fname->st); TALLOC_FREE(streams); return NT_STATUS_OK; } - TALLOC_FREE(result); + DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n", + smb_fname->stream_name, streams[i].name)); + - result = talloc_asprintf(mem_ctx, "%s%s", basepath, streams[i].name); - if (result == NULL) { + TALLOC_FREE(smb_fname->stream_name); + smb_fname->stream_name = talloc_strdup(mem_ctx, streams[i].name); + + TALLOC_FREE(result); + status = get_full_smb_filename(mem_ctx, smb_fname, &result); + if (!NT_STATUS_IS_OK(status)) { status = NT_STATUS_NO_MEMORY; goto fail; } - SET_STAT_INVALID(*pst); + SET_STAT_INVALID(smb_fname->st); - if (SMB_VFS_STAT(conn, result, pst) == 0) { + if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) { stat_cache_add(orig_path, result, conn->case_sensitive); } - *path = result; TALLOC_FREE(streams); return NT_STATUS_OK; diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index efbc05ceb0..7f99a186aa 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -515,8 +515,8 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, { char *p = NULL; char *q = NULL; - SMB_STRUCT_STAT sbuf; NTSTATUS status; + struct smb_filename *smb_fname = NULL; char *localpath = NULL; char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/' components). */ @@ -536,13 +536,22 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, * think this is needed. JRA. */ - status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath, - NULL, &sbuf); + status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname, + search_flag ? UCF_ALLOW_WCARD_LCOMP : 0); + if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) { return status; } + status = get_full_smb_filename(ctx, smb_fname, &localpath); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(smb_fname); + return status; + } + + TALLOC_FREE(smb_fname); + /* Optimization - check if we can redirect the whole path. */ if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) { diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 7e75eea6b4..d51c9a6d67 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1155,11 +1155,10 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, const char *newname_in, uint32 attrs) { - SMB_STRUCT_STAT sbuf1, sbuf2; + struct smb_filename *smb_fname = NULL; + struct smb_filename *smb_fname_new = NULL; char *oldname = NULL; char *newname = NULL; - char *last_component_oldname = NULL; - char *last_component_newname = NULL; files_struct *fsp1,*fsp2; uint32 fattr; int info; @@ -1167,59 +1166,69 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, NTSTATUS status = NT_STATUS_OK; char *parent; - ZERO_STRUCT(sbuf1); - ZERO_STRUCT(sbuf2); - if (!CAN_WRITE(conn)) { - return NT_STATUS_MEDIA_WRITE_PROTECTED; + status = NT_STATUS_MEDIA_WRITE_PROTECTED; + goto out; } - status = unix_convert(ctx, conn, oldname_in, False, &oldname, - &last_component_oldname, &sbuf1); + status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; + } + + status = get_full_smb_filename(ctx, smb_fname, &oldname); + if (!NT_STATUS_IS_OK(status)) { + goto out; } status = check_name(conn, oldname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } /* Source must already exist. */ - if (!VALID_STAT(sbuf1)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + if (!VALID_STAT(smb_fname->st)) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto out; } /* Ensure attributes match. */ - fattr = dos_mode(conn,oldname,&sbuf1); + fattr = dos_mode(conn, oldname, &smb_fname->st); if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) { - return NT_STATUS_NO_SUCH_FILE; + status = NT_STATUS_NO_SUCH_FILE; + goto out; } - status = unix_convert(ctx, conn, newname_in, False, &newname, - &last_component_newname, &sbuf2); + status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; + } + + status = get_full_smb_filename(ctx, smb_fname_new, &newname); + if (!NT_STATUS_IS_OK(status)) { + goto out; } status = check_name(conn, newname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } /* Disallow if newname already exists. */ - if (VALID_STAT(sbuf2)) { - return NT_STATUS_OBJECT_NAME_COLLISION; + if (VALID_STAT(smb_fname_new->st)) { + status = NT_STATUS_OBJECT_NAME_COLLISION; + goto out; } /* No links from a directory. */ - if (S_ISDIR(sbuf1.st_mode)) { - return NT_STATUS_FILE_IS_A_DIRECTORY; + if (S_ISDIR(smb_fname->st.st_mode)) { + status = NT_STATUS_FILE_IS_A_DIRECTORY; + goto out; } /* Ensure this is within the share. */ status = check_reduced_name(conn, oldname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } DEBUG(10,("copy_internals: doing file copy %s to %s\n", @@ -1243,10 +1252,10 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, NULL, /* ea_list */ &fsp1, /* result */ &info, /* pinfo */ - &sbuf1); /* psbuf */ + &smb_fname->st); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } status = SMB_VFS_CREATE_FILE( @@ -1267,15 +1276,15 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, NULL, /* ea_list */ &fsp2, /* result */ &info, /* pinfo */ - &sbuf2); /* psbuf */ + &smb_fname_new->st); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { close_file(NULL, fsp1, ERROR_CLOSE); - return status; + goto out; } - if (sbuf1.st_size) { - ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size); + if (smb_fname->st.st_size) { + ret = vfs_transfer_file(fsp1, fsp2, smb_fname->st.st_size); } /* @@ -1287,7 +1296,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, close_file(NULL, fsp1, NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - set_close_write_time(fsp2, get_mtimespec(&sbuf1)); + set_close_write_time(fsp2, get_mtimespec(&smb_fname->st)); status = close_file(NULL, fsp2, NORMAL_CLOSE); @@ -1295,15 +1304,24 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, creates the file. This isn't the correct thing to do in the copy case. JRA */ if (!parent_dirname(talloc_tos(), newname, &parent, NULL)) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } - file_set_dosmode(conn, newname, fattr, &sbuf2, parent, false); + file_set_dosmode(conn, newname, fattr, &smb_fname_new->st, parent, + false); TALLOC_FREE(parent); - if (ret < (SMB_OFF_T)sbuf1.st_size) { - return NT_STATUS_DISK_FULL; + if (ret < (SMB_OFF_T)smb_fname->st.st_size) { + status = NT_STATUS_DISK_FULL; + goto out; + } + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } + if (smb_fname_new) { + TALLOC_FREE(smb_fname_new); } - if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("copy_internals: Error %s copy file %s to %s\n", nt_errstr(status), oldname, newname)); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index a0ae82a73c..e6f523a162 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3442,16 +3442,27 @@ NTSTATUS create_file_default(connection_struct *conn, } if (create_file_flags & CFF_DOS_PATH) { + struct smb_filename *smb_fname = NULL; char *converted_fname; SET_STAT_INVALID(sbuf); - status = unix_convert(talloc_tos(), conn, fname, False, - &converted_fname, NULL, &sbuf); + status = unix_convert(talloc_tos(), conn, fname, &smb_fname, + 0); if (!NT_STATUS_IS_OK(status)) { goto fail; } + + status = get_full_smb_filename(talloc_tos(), smb_fname, + &converted_fname); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(smb_fname); + goto fail; + } + + sbuf = smb_fname->st; fname = converted_fname; + TALLOC_FREE(smb_fname); } else { if (psbuf != NULL) { sbuf = *psbuf; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 879550bb2e..c15ebbe35e 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -966,8 +966,8 @@ static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status) void reply_checkpath(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; char *name = NULL; - SMB_STRUCT_STAT sbuf; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -999,7 +999,12 @@ void reply_checkpath(struct smb_request *req) DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0))); - status = unix_convert(ctx, conn, name, False, &name, NULL, &sbuf); + status = unix_convert(ctx, conn, name, &smb_fname, 0); + if (!NT_STATUS_IS_OK(status)) { + goto path_err; + } + + status = get_full_smb_filename(ctx, smb_fname, &name); if (!NT_STATUS_IS_OK(status)) { goto path_err; } @@ -1010,25 +1015,32 @@ void reply_checkpath(struct smb_request *req) goto path_err; } - if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) { + if (!VALID_STAT(smb_fname->st) && + (SMB_VFS_STAT(conn, name, &smb_fname->st) != 0)) { DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno))); status = map_nt_error_from_unix(errno); goto path_err; } - if (!S_ISDIR(sbuf.st_mode)) { + if (!S_ISDIR(smb_fname->st.st_mode)) { reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY, ERRDOS, ERRbadpath); - END_PROFILE(SMBcheckpath); - return; + goto out; } reply_outbuf(req, 0, 0); - + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } END_PROFILE(SMBcheckpath); return; - path_err: + path_err: + + if (smb_fname) { + TALLOC_FREE(smb_fname); + } END_PROFILE(SMBcheckpath); @@ -1061,8 +1073,8 @@ void reply_checkpath(struct smb_request *req) void reply_getatr(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; char *fname = NULL; - SMB_STRUCT_STAT sbuf; int mode=0; SMB_OFF_T size=0; time_t mtime=0; @@ -1076,8 +1088,7 @@ void reply_getatr(struct smb_request *req) p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBgetatr); - return; + goto out; } status = resolve_dfspath(ctx, conn, @@ -1088,12 +1099,10 @@ void reply_getatr(struct smb_request *req) if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBgetatr); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBgetatr); - return; + goto out; } /* dos smetimes asks for a stat of "" - it returns a "hidden directory" @@ -1106,29 +1115,32 @@ void reply_getatr(struct smb_request *req) size = 0; mtime = 0; } else { - status = unix_convert(ctx, conn, fname, False, &fname, NULL,&sbuf); + status = unix_convert(ctx, conn, fname, &smb_fname, 0); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBgetatr); - return; + goto out; + } + status = get_full_smb_filename(ctx, smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; } status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status))); reply_nterror(req, status); - END_PROFILE(SMBgetatr); - return; + goto out; } - if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) { + if (!VALID_STAT(smb_fname->st) && + (SMB_VFS_STAT(conn, fname, &smb_fname->st) != 0)) { DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno))); reply_unixerror(req, ERRDOS,ERRbadfile); - END_PROFILE(SMBgetatr); - return; + goto out; } - mode = dos_mode(conn,fname,&sbuf); - size = sbuf.st_size; - mtime = sbuf.st_mtime; + mode = dos_mode(conn, fname, &smb_fname->st); + size = smb_fname->st.st_size; + mtime = smb_fname->st.st_mtime; if (mode & aDIR) { size = 0; } @@ -1151,6 +1163,10 @@ void reply_getatr(struct smb_request *req) DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) ); + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } END_PROFILE(SMBgetatr); return; } @@ -1163,10 +1179,10 @@ void reply_setatr(struct smb_request *req) { struct smb_file_time ft; connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; char *fname = NULL; int mode; time_t mtime; - SMB_STRUCT_STAT sbuf; const char *p; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -1177,15 +1193,14 @@ void reply_setatr(struct smb_request *req) if (req->wct < 2) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } p = (const char *)req->buf + 1; p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBsetatr); - return; + goto out; } status = resolve_dfspath(ctx, conn, @@ -1196,26 +1211,28 @@ void reply_setatr(struct smb_request *req) if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBsetatr); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBsetatr); - return; + goto out; } - status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); + status = unix_convert(ctx, conn, fname, &smb_fname, 0); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBsetatr); - return; + goto out; + } + + status = get_full_smb_filename(ctx, smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; } status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBsetatr); - return; + goto out; } if (fname[0] == '.' && fname[1] == '\0') { @@ -1224,8 +1241,7 @@ void reply_setatr(struct smb_request *req) * condition. Might be moved to somewhere else later -- vl */ reply_nterror(req, NT_STATUS_ACCESS_DENIED); - END_PROFILE(SMBsetatr); - return; + goto out; } mode = SVAL(req->vwv+0, 0); @@ -1233,30 +1249,32 @@ void reply_setatr(struct smb_request *req) ft.mtime = convert_time_t_to_timespec(mtime); status = smb_set_file_time(conn, NULL, fname, - &sbuf, &ft, true); + &smb_fname->st, &ft, true); if (!NT_STATUS_IS_OK(status)) { reply_unixerror(req, ERRDOS, ERRnoaccess); - END_PROFILE(SMBsetatr); - return; + goto out; } if (mode != FILE_ATTRIBUTE_NORMAL) { - if (VALID_STAT_OF_DIR(sbuf)) + if (VALID_STAT_OF_DIR(smb_fname->st)) mode |= aDIR; else mode &= ~aDIR; - if (file_set_dosmode(conn,fname,mode,&sbuf,NULL,false) != 0) { + if (file_set_dosmode(conn, fname, mode, &smb_fname->st, NULL, + false) != 0) { reply_unixerror(req, ERRDOS, ERRnoaccess); - END_PROFILE(SMBsetatr); - return; + goto out; } } reply_outbuf(req, 0, 0); DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) ); - + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } END_PROFILE(SMBsetatr); return; } @@ -1399,10 +1417,18 @@ void reply_search(struct smb_request *req) /* dirtype &= ~aDIR; */ if (status_len == 0) { - SMB_STRUCT_STAT sbuf; + struct smb_filename *smb_fname = NULL; - nt_status = unix_convert(ctx, conn, path, True, - &directory, NULL, &sbuf); + nt_status = unix_convert(ctx, conn, path, &smb_fname, + UCF_ALLOW_WCARD_LCOMP); + if (!NT_STATUS_IS_OK(nt_status)) { + reply_nterror(req, nt_status); + END_PROFILE(SMBsearch); + return; + } + + nt_status = get_full_smb_filename(ctx, smb_fname, &directory); + TALLOC_FREE(smb_fname); if (!NT_STATUS_IS_OK(nt_status)) { reply_nterror(req, nt_status); END_PROFILE(SMBsearch); @@ -2142,12 +2168,12 @@ void reply_mknew(struct smb_request *req) void reply_ctemp(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 fattr; files_struct *fsp; int oplock_request; int tmpfd; - SMB_STRUCT_STAT sbuf; char *s; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -2156,8 +2182,7 @@ void reply_ctemp(struct smb_request *req) if (req->wct < 3) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBctemp); - return; + goto out; } fattr = SVAL(req->vwv+0, 0); @@ -2167,8 +2192,7 @@ void reply_ctemp(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBctemp); - return; + goto out; } if (*fname) { fname = talloc_asprintf(ctx, @@ -2180,8 +2204,7 @@ void reply_ctemp(struct smb_request *req) if (!fname) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBctemp); - return; + goto out; } status = resolve_dfspath(ctx, conn, @@ -2192,37 +2215,38 @@ void reply_ctemp(struct smb_request *req) if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBctemp); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBctemp); - return; + goto out; } - status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); + status = unix_convert(ctx, conn, fname, &smb_fname, 0); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBctemp); - return; + goto out; + } + + status = get_full_smb_filename(ctx, smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; } status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBctemp); - return; + goto out; } tmpfd = mkstemp(fname); if (tmpfd == -1) { reply_unixerror(req, ERRDOS, ERRnoaccess); - END_PROFILE(SMBctemp); - return; + goto out; } - SET_STAT_INVALID(sbuf); - SMB_VFS_STAT(conn,fname,&sbuf); + SET_STAT_INVALID(smb_fname->st); + SMB_VFS_STAT(conn, fname, &smb_fname->st); /* We should fail if file does not exist. */ status = SMB_VFS_CREATE_FILE( @@ -2242,7 +2266,7 @@ void reply_ctemp(struct smb_request *req) NULL, /* ea_list */ &fsp, /* result */ NULL, /* pinfo */ - &sbuf); /* psbuf */ + &smb_fname->st); /* psbuf */ /* close fd from mkstemp() */ close(tmpfd); @@ -2250,12 +2274,10 @@ void reply_ctemp(struct smb_request *req) if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - END_PROFILE(SMBctemp); - return; + goto out; } reply_openerror(req, status); - END_PROFILE(SMBctemp); - return; + goto out; } reply_outbuf(req, 1, 0); @@ -2277,8 +2299,7 @@ void reply_ctemp(struct smb_request *req) if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE) == -1) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBctemp); - return; + goto out; } if (oplock_request && lp_fake_oplocks(SNUM(conn))) { @@ -2293,8 +2314,11 @@ void reply_ctemp(struct smb_request *req) DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fsp->fsp_name ) ); DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fsp->fsp_name, - fsp->fh->fd, (unsigned int)sbuf.st_mode ) ); - + fsp->fh->fd, (unsigned int)smb_fname->st.st_mode)); + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } END_PROFILE(SMBctemp); return; } @@ -2479,24 +2503,33 @@ static NTSTATUS do_unlink(connection_struct *conn, NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, uint32 dirtype, const char *name_in, bool has_wild) { + struct smb_filename *smb_fname = NULL; const char *directory = NULL; char *mask = NULL; char *name = NULL; char *p = NULL; int count=0; NTSTATUS status = NT_STATUS_OK; - SMB_STRUCT_STAT sbuf, st; + SMB_STRUCT_STAT st; TALLOC_CTX *ctx = talloc_tos(); - status = unix_convert(ctx, conn, name_in, has_wild, &name, NULL, &sbuf); + status = unix_convert(ctx, conn, name_in, &smb_fname, + has_wild ? UCF_ALLOW_WCARD_LCOMP : 0); if (!NT_STATUS_IS_OK(status)) { return status; } + status = get_full_smb_filename(ctx, smb_fname, &name); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(smb_fname); + return status; + } + p = strrchr_m(name,'/'); if (!p) { directory = talloc_strdup(ctx, "."); if (!directory) { + TALLOC_FREE(smb_fname); return NT_STATUS_NO_MEMORY; } mask = name; @@ -2515,7 +2548,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) { + if (!VALID_STAT(smb_fname->st) && mangle_is_mangled(mask,conn->params)) { char *new_mask = NULL; mangle_lookup_name_from_8_3(ctx, mask, @@ -2525,6 +2558,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, mask = new_mask; } } + TALLOC_FREE(smb_fname); if (!has_wild) { directory = talloc_asprintf(ctx, @@ -5141,9 +5175,9 @@ void reply_printwrite(struct smb_request *req) void reply_mkdir(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_dname = NULL; char *directory = NULL; NTSTATUS status; - SMB_STRUCT_STAT sbuf; TALLOC_CTX *ctx = talloc_tos(); START_PROFILE(SMBmkdir); @@ -5152,8 +5186,7 @@ void reply_mkdir(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBmkdir); - return; + goto out; } status = resolve_dfspath(ctx, conn, @@ -5164,26 +5197,28 @@ void reply_mkdir(struct smb_request *req) if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBmkdir); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBmkdir); - return; + goto out; } - status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf); + status = unix_convert(ctx, conn, directory, &smb_dname, 0); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBmkdir); - return; + goto out; + } + + status = get_full_smb_filename(ctx, smb_dname, &directory); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; } status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBmkdir); - return; + goto out; } status = create_directory(conn, req, directory); @@ -5204,14 +5239,16 @@ void reply_mkdir(struct smb_request *req) } reply_nterror(req, status); - END_PROFILE(SMBmkdir); - return; + goto out; } reply_outbuf(req, 0, 0); DEBUG( 3, ( "mkdir %s\n", directory ) ); - + out: + if (smb_dname) { + TALLOC_FREE(smb_dname); + } END_PROFILE(SMBmkdir); return; } @@ -5418,8 +5455,8 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, void reply_rmdir(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_dname = NULL; char *directory = NULL; - SMB_STRUCT_STAT sbuf; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -5429,8 +5466,7 @@ void reply_rmdir(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBrmdir); - return; + goto out; } status = resolve_dfspath(ctx, conn, @@ -5441,41 +5477,44 @@ void reply_rmdir(struct smb_request *req) if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBrmdir); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBrmdir); - return; + goto out; } - status = unix_convert(ctx, conn, directory, False, &directory, - NULL, &sbuf); + status = unix_convert(ctx, conn, directory, &smb_dname, 0); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBrmdir); - return; + goto out; + } + + status = get_full_smb_filename(ctx, smb_dname, &directory); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; } status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBrmdir); - return; + goto out; } dptr_closepath(directory, req->smbpid); status = rmdir_internals(ctx, conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBrmdir); - return; + goto out; } reply_outbuf(req, 0, 0); DEBUG( 3, ( "rmdir %s\n", directory ) ); - + out: + if (smb_dname) { + TALLOC_FREE(smb_dname); + } END_PROFILE(SMBrmdir); return; } @@ -5936,35 +5975,42 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, bool dest_has_wild, uint32_t access_mask) { + struct smb_filename *smb_fname = NULL; + struct smb_filename *smb_fname_new = NULL; char *directory = NULL; char *mask = NULL; - char *last_component_src = NULL; - char *last_component_dest = NULL; char *name = NULL; char *newname = NULL; char *p; int count=0; NTSTATUS status = NT_STATUS_OK; - SMB_STRUCT_STAT sbuf1, sbuf2; struct smb_Dir *dir_hnd = NULL; const char *dname; long offset = 0; int create_options = 0; bool posix_pathnames = lp_posix_pathnames(); - ZERO_STRUCT(sbuf1); - ZERO_STRUCT(sbuf2); + status = unix_convert(ctx, conn, name_in, &smb_fname, + src_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = get_full_smb_filename(ctx, smb_fname, &name); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } - status = unix_convert(ctx, conn, name_in, src_has_wild, &name, - &last_component_src, &sbuf1); + status = unix_convert(ctx, conn, newname_in, &smb_fname_new, + (UCF_SAVE_LCOMP | + (dest_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0))); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } - status = unix_convert(ctx, conn, newname_in, dest_has_wild, &newname, - &last_component_dest, &sbuf2); + status = get_full_smb_filename(ctx, smb_fname_new, &newname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } /* @@ -5980,14 +6026,16 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, if (!p) { directory = talloc_strdup(ctx, "."); if (!directory) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } mask = name; } else { *p = 0; directory = talloc_strdup(ctx, name); if (!directory) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } mask = p+1; *p = '/'; /* Replace needed for exceptional test below. */ @@ -6002,7 +6050,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { + if (!VALID_STAT(smb_fname->st) && mangle_is_mangled(mask, conn->params)) { char *new_mask = NULL; mangle_lookup_name_from_8_3(ctx, mask, @@ -6024,7 +6072,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, "/%s", mask); if (!directory) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } /* Ensure newname contains a '/' also */ @@ -6033,7 +6082,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, "./%s", newname); if (!newname) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } } @@ -6043,7 +6093,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, "last_component_dest = %s\n", conn->case_sensitive, conn->case_preserve, conn->short_case_preserve, directory, - newname, last_component_dest)); + newname, smb_fname_new->original_lcomp)); /* The dest name still may have wildcards. */ if (dest_has_wild) { @@ -6054,19 +6104,20 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, "%s %s failed\n", directory, newname)); - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } newname = mod_newname; } - ZERO_STRUCT(sbuf1); + ZERO_STRUCT(smb_fname->st); if (posix_pathnames) { - SMB_VFS_LSTAT(conn, directory, &sbuf1); + SMB_VFS_LSTAT(conn, directory, &smb_fname->st); } else { - SMB_VFS_STAT(conn, directory, &sbuf1); + SMB_VFS_STAT(conn, directory, &smb_fname->st); } - if (S_ISDIR(sbuf1.st_mode)) { + if (S_ISDIR(smb_fname->st.st_mode)) { create_options |= FILE_DIRECTORY_FILE; } @@ -6088,16 +6139,16 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, NULL, /* ea_list */ &fsp, /* result */ NULL, /* pinfo */ - &sbuf1); /* psbuf */ + &smb_fname->st); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Could not open rename source %s: %s\n", directory, nt_errstr(status))); - return status; + goto out; } status = rename_internals_fsp(conn, fsp, newname, - last_component_dest, + smb_fname_new->original_lcomp, attrs, replace_if_exists); close_file(req, fsp, NORMAL_CLOSE); @@ -6105,7 +6156,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n", nt_errstr(status), directory,newname)); - return status; + goto out; } /* @@ -6118,12 +6169,13 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, attrs); if (dir_hnd == NULL) { - return map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); + goto out; } status = NT_STATUS_NO_SUCH_FILE; @@ -6132,7 +6184,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, * - gentest fix. JRA */ - while ((dname = ReadDirName(dir_hnd, &offset, &sbuf1))) { + while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname->st))) { files_struct *fsp = NULL; char *fname = NULL; char *destname = NULL; @@ -6147,7 +6199,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, } } - if (!is_visible_file(conn, directory, dname, &sbuf1, False)) { + if (!is_visible_file(conn, directory, dname, &smb_fname->st, + False)) { continue; } @@ -6165,7 +6218,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, directory, dname); if (!fname) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } if (!resolve_wildcards(ctx, @@ -6176,19 +6230,20 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, continue; } if (!destname) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto out; } - ZERO_STRUCT(sbuf1); + ZERO_STRUCT(smb_fname->st); if (posix_pathnames) { - SMB_VFS_LSTAT(conn, fname, &sbuf1); + SMB_VFS_LSTAT(conn, fname, &smb_fname->st); } else { - SMB_VFS_STAT(conn, fname, &sbuf1); + SMB_VFS_STAT(conn, fname, &smb_fname->st); } create_options = 0; - if (S_ISDIR(sbuf1.st_mode)) { + if (S_ISDIR(smb_fname->st.st_mode)) { create_options |= FILE_DIRECTORY_FILE; } @@ -6210,7 +6265,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, NULL, /* ea_list */ &fsp, /* result */ NULL, /* pinfo */ - &sbuf1); /* psbuf */ + &smb_fname->st); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE " @@ -6245,6 +6300,13 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, status = map_nt_error_from_unix(errno); } + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } + if (smb_fname_new) { + TALLOC_FREE(smb_fname_new); + } return status; } @@ -6505,6 +6567,8 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, void reply_copy(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; + struct smb_filename *smb_fname_new = NULL; char *name = NULL; char *newname = NULL; char *directory = NULL; @@ -6520,7 +6584,6 @@ void reply_copy(struct smb_request *req) bool target_is_directory=False; bool source_has_wild = False; bool dest_has_wild = False; - SMB_STRUCT_STAT sbuf1, sbuf2; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); @@ -6528,8 +6591,7 @@ void reply_copy(struct smb_request *req) if (req->wct < 3) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBcopy); - return; + goto out; } tid2 = SVAL(req->vwv+0, 0); @@ -6541,15 +6603,13 @@ void reply_copy(struct smb_request *req) &status, &source_has_wild); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE, &status, &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); @@ -6558,8 +6618,7 @@ void reply_copy(struct smb_request *req) /* can't currently handle inter share copies XXXX */ DEBUG(3,("Rejecting inter-share copy\n")); reply_doserror(req, ERRSRV, ERRinvdevice); - END_PROFILE(SMBcopy); - return; + goto out; } status = resolve_dfspath_wcard(ctx, conn, @@ -6571,12 +6630,10 @@ void reply_copy(struct smb_request *req) if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBcopy); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } status = resolve_dfspath_wcard(ctx, conn, @@ -6588,50 +6645,55 @@ void reply_copy(struct smb_request *req) if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - END_PROFILE(SMBcopy); - return; + goto out; } reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } - status = unix_convert(ctx, conn, name, source_has_wild, - &name, NULL, &sbuf1); + status = unix_convert(ctx, conn, name, &smb_fname, + source_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } - status = unix_convert(ctx, conn, newname, dest_has_wild, - &newname, NULL, &sbuf2); + status = get_full_smb_filename(ctx, smb_fname, &name); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; + } + + status = unix_convert(ctx, conn, newname, &smb_fname_new, + dest_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; + } + + status = get_full_smb_filename(ctx, smb_fname_new, &newname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; } - target_is_directory = VALID_STAT_OF_DIR(sbuf2); + target_is_directory = VALID_STAT_OF_DIR(smb_fname_new->st); if ((flags&1) && target_is_directory) { reply_doserror(req, ERRDOS, ERRbadfile); - END_PROFILE(SMBcopy); - return; + goto out; } if ((flags&2) && !target_is_directory) { reply_doserror(req, ERRDOS, ERRbadpath); - END_PROFILE(SMBcopy); - return; + goto out; } - if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) { + if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname->st)) { /* wants a tree copy! XXXX */ DEBUG(3,("Rejecting tree copy\n")); reply_doserror(req, ERRSRV, ERRerror); - END_PROFILE(SMBcopy); - return; + goto out; } p = strrchr_m(name,'/'); @@ -6645,8 +6707,7 @@ void reply_copy(struct smb_request *req) if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBcopy); - return; + goto out; } /* @@ -6658,7 +6719,8 @@ void reply_copy(struct smb_request *req) * Tine Smukavec <valentin.smukavec@hermes.si>. */ - if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) { + if (!VALID_STAT(smb_fname->st) && + mangle_is_mangled(mask, conn->params)) { char *new_mask = NULL; mangle_lookup_name_from_8_3(ctx, mask, @@ -6678,8 +6740,7 @@ void reply_copy(struct smb_request *req) if (!resolve_wildcards(ctx, directory,newname,&mod_newname)) { reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBcopy); - return; + goto out; } newname = mod_newname; } @@ -6687,15 +6748,13 @@ void reply_copy(struct smb_request *req) status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } status = check_name(conn, newname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } status = copy_file(ctx,conn,directory,newname,ofun, @@ -6703,8 +6762,7 @@ void reply_copy(struct smb_request *req) if(!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } else { count++; } @@ -6720,21 +6778,20 @@ void reply_copy(struct smb_request *req) status = check_name(conn, directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, 0); if (dir_hnd == NULL) { status = map_nt_error_from_unix(errno); reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } error = ERRbadfile; - while ((dname = ReadDirName(dir_hnd, &offset, &sbuf1))) { + while ((dname = ReadDirName(dir_hnd, &offset, + &smb_fname->st))) { char *destname = NULL; char *fname = NULL; @@ -6742,7 +6799,8 @@ void reply_copy(struct smb_request *req) continue; } - if (!is_visible_file(conn, directory, dname, &sbuf1, False)) { + if (!is_visible_file(conn, directory, dname, + &smb_fname->st, False)) { continue; } @@ -6758,8 +6816,7 @@ void reply_copy(struct smb_request *req) if (!fname) { TALLOC_FREE(dir_hnd); reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBcopy); - return; + goto out; } if (!resolve_wildcards(ctx, @@ -6769,24 +6826,21 @@ void reply_copy(struct smb_request *req) if (!destname) { TALLOC_FREE(dir_hnd); reply_nterror(req, NT_STATUS_NO_MEMORY); - END_PROFILE(SMBcopy); - return; + goto out; } status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } status = check_name(conn, destname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); reply_nterror(req, status); - END_PROFILE(SMBcopy); - return; + goto out; } DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname)); @@ -6807,18 +6861,22 @@ void reply_copy(struct smb_request *req) /* Error on close... */ errno = err; reply_unixerror(req, ERRHRD, ERRgeneral); - END_PROFILE(SMBcopy); - return; + goto out; } reply_doserror(req, ERRDOS, error); - END_PROFILE(SMBcopy); - return; + goto out; } reply_outbuf(req, 1, 0); SSVAL(req->outbuf,smb_vwv0,count); - + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } + if (smb_fname_new) { + TALLOC_FREE(smb_fname_new); + } END_PROFILE(SMBcopy); return; } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index edbb0dfc4d..a498e24d74 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1882,6 +1882,7 @@ static void call_trans2findfirst(connection_struct *conn, maxentries then so be it. We assume that the redirector has enough room for the fixed number of parameter bytes it has requested. */ + struct smb_filename *smb_dname = NULL; char *params = *pparams; char *pdata = *ppdata; char *data_end; @@ -1904,7 +1905,6 @@ static void call_trans2findfirst(connection_struct *conn, bool out_of_space = False; int space_remaining; bool mask_contains_wcard = False; - SMB_STRUCT_STAT sbuf; struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); @@ -1981,7 +1981,17 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", return; } - ntstatus = unix_convert(ctx, conn, directory, True, &directory, &mask, &sbuf); + ntstatus = unix_convert(ctx, conn, directory, &smb_dname, + (UCF_SAVE_LCOMP | UCF_ALLOW_WCARD_LCOMP)); + if (!NT_STATUS_IS_OK(ntstatus)) { + reply_nterror(req, ntstatus); + return; + } + + mask = smb_dname->original_lcomp; + + ntstatus = get_full_smb_filename(ctx, smb_dname, &directory); + TALLOC_FREE(smb_dname); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); return; @@ -3834,6 +3844,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, SMB_STRUCT_STAT sbuf; char *dos_fname = NULL; char *fname = NULL; + struct smb_filename *smb_fname = NULL; char *fullpathname; char *base_name; char *p; @@ -3981,11 +3992,20 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } - status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); + status = unix_convert(ctx, conn, fname, &smb_fname, 0); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + sbuf = smb_fname->st; + + status = get_full_smb_filename(ctx, smb_fname, &fname); + TALLOC_FREE(smb_fname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; } + status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status))); @@ -4821,57 +4841,64 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, const char *oldname_in, const char *newname_in) { - SMB_STRUCT_STAT sbuf1, sbuf2; - char *last_component_oldname = NULL; - char *last_component_newname = NULL; + struct smb_filename *smb_fname = NULL; + struct smb_filename *smb_fname_new = NULL; char *oldname = NULL; char *newname = NULL; NTSTATUS status = NT_STATUS_OK; - ZERO_STRUCT(sbuf1); - ZERO_STRUCT(sbuf2); + status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } - status = unix_convert(ctx, conn, oldname_in, False, &oldname, - &last_component_oldname, &sbuf1); + status = get_full_smb_filename(ctx, smb_fname, &oldname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } status = check_name(conn, oldname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } /* source must already exist. */ - if (!VALID_STAT(sbuf1)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + if (!VALID_STAT(smb_fname->st)) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto out; } - status = unix_convert(ctx, conn, newname_in, False, &newname, - &last_component_newname, &sbuf2); + status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; + } + + status = get_full_smb_filename(ctx, smb_fname_new, &newname); + if (!NT_STATUS_IS_OK(status)) { + goto out; } status = check_name(conn, newname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } /* Disallow if newname already exists. */ - if (VALID_STAT(sbuf2)) { - return NT_STATUS_OBJECT_NAME_COLLISION; + if (VALID_STAT(smb_fname_new->st)) { + status = NT_STATUS_OBJECT_NAME_COLLISION; + goto out; } /* No links from a directory. */ - if (S_ISDIR(sbuf1.st_mode)) { - return NT_STATUS_FILE_IS_A_DIRECTORY; + if (S_ISDIR(smb_fname->st.st_mode)) { + status = NT_STATUS_FILE_IS_A_DIRECTORY; + goto out; } /* Ensure this is within the share. */ status = check_reduced_name(conn, oldname); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname )); @@ -4879,9 +4906,15 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, if (SMB_VFS_LINK(conn,oldname,newname) != 0) { status = map_nt_error_from_unix(errno); DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n", - nt_errstr(status), newname, oldname)); + nt_errstr(status), newname, oldname)); + } + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } + if (smb_fname_new) { + TALLOC_FREE(smb_fname_new); } - return status; } @@ -5382,9 +5415,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, uint32 len; char *newname = NULL; char *base_name = NULL; + struct smb_filename *smb_fname = NULL; bool dest_has_wcard = False; - SMB_STRUCT_STAT sbuf; - char *newname_last_component = NULL; NTSTATUS status = NT_STATUS_OK; char *p; TALLOC_CTX *ctx = talloc_tos(); @@ -5393,8 +5425,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - ZERO_STRUCT(sbuf); - overwrite = (CVAL(pdata,0) ? True : False); root_fid = IVAL(pdata,4); len = IVAL(pdata,8); @@ -5466,10 +5496,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_NO_MEMORY; } - status = unix_convert(ctx, conn, newname, False, - &newname, - &newname_last_component, - &sbuf); + status = unix_convert(ctx, conn, newname, &smb_fname, + UCF_SAVE_LCOMP); /* If an error we expect this to be * NT_STATUS_OBJECT_PATH_NOT_FOUND */ @@ -5477,7 +5505,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, status)) { - return status; + goto out; } } @@ -5485,8 +5513,9 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", fsp->fnum, fsp->fsp_name, base_name )); status = rename_internals_fsp(conn, fsp, base_name, - newname_last_component, 0, - overwrite); + smb_fname ? + smb_fname->original_lcomp : NULL, + 0, overwrite); } else { DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n", fname, base_name )); @@ -5494,7 +5523,10 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, overwrite, False, dest_has_wcard, FILE_WRITE_ATTRIBUTES); } - + out: + if (smb_fname) { + TALLOC_FREE(smb_fname); + } return status; } @@ -6700,6 +6732,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, uint16 info_level; SMB_STRUCT_STAT sbuf; char *fname = NULL; + struct smb_filename *smb_fname = NULL; files_struct *fsp = NULL; NTSTATUS status = NT_STATUS_OK; int data_return_size = 0; @@ -6814,8 +6847,15 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - status = unix_convert(ctx, conn, fname, False, - &fname, NULL, &sbuf); + status = unix_convert(ctx, conn, fname, &smb_fname, 0); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + sbuf = smb_fname->st; + + status = get_full_smb_filename(ctx, smb_fname, &fname); + TALLOC_FREE(smb_fname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; @@ -7129,10 +7169,10 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, char **ppdata, int total_data, unsigned int max_data_bytes) { + struct smb_filename *smb_dname = NULL; char *params = *pparams; char *pdata = *ppdata; char *directory = NULL; - SMB_STRUCT_STAT sbuf; NTSTATUS status = NT_STATUS_OK; struct ea_list *ea_list = NULL; TALLOC_CTX *ctx = talloc_tos(); @@ -7157,7 +7197,13 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); - status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf); + status = unix_convert(ctx, conn, directory, &smb_dname, 0); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = get_full_smb_filename(ctx, smb_dname, &directory); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); return; |