summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/smbd/reply.c117
1 files changed, 64 insertions, 53 deletions
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index cff1aa7498..8790bd5b91 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -2422,13 +2422,14 @@ void reply_ctemp(struct smb_request *req)
{
connection_struct *conn = req->conn;
struct smb_filename *smb_fname = NULL;
+ char *wire_name = NULL;
char *fname = NULL;
uint32 fattr;
files_struct *fsp;
int oplock_request;
- int tmpfd;
char *s;
NTSTATUS status;
+ int i;
TALLOC_CTX *ctx = talloc_tos();
START_PROFILE(SMBctemp);
@@ -2441,77 +2442,86 @@ void reply_ctemp(struct smb_request *req)
fattr = SVAL(req->vwv+0, 0);
oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
- srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf+1,
+ srvstr_get_path_req(ctx, req, &wire_name, (const char *)req->buf+1,
STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
goto out;
}
- if (*fname) {
- fname = talloc_asprintf(ctx,
- "%s/TMXXXXXX",
- fname);
- } else {
- fname = talloc_strdup(ctx, "TMXXXXXX");
- }
- if (!fname) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- goto out;
- }
+ for (i = 0; i < 10; i++) {
+ if (*wire_name) {
+ fname = talloc_asprintf(ctx,
+ "%s/TMP%s",
+ wire_name,
+ generate_random_str_list(ctx, 5, "0123456789"));
+ } else {
+ fname = talloc_asprintf(ctx,
+ "TMP%s",
+ generate_random_str_list(ctx, 5, "0123456789"));
+ }
- status = filename_convert(ctx, conn,
+ if (!fname) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ goto out;
+ }
+
+ status = filename_convert(ctx, conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
fname,
0,
NULL,
&smb_fname);
- if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
- reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
ERRSRV, ERRbadpath);
+ goto out;
+ }
+ reply_nterror(req, status);
goto out;
}
- reply_nterror(req, status);
- goto out;
- }
-
- tmpfd = mkstemp(smb_fname->base_name);
- if (tmpfd == -1) {
- reply_nterror(req, map_nt_error_from_unix(errno));
- goto out;
- }
- SMB_VFS_STAT(conn, smb_fname);
-
- /* We should fail if file does not exist. */
- status = SMB_VFS_CREATE_FILE(
- conn, /* conn */
- req, /* req */
- 0, /* root_dir_fid */
- smb_fname, /* fname */
- FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
- FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
- FILE_OPEN, /* create_disposition*/
- 0, /* create_options */
- fattr, /* file_attributes */
- oplock_request, /* oplock_request */
- 0, /* allocation_size */
- 0, /* private_flags */
- NULL, /* sd */
- NULL, /* ea_list */
- &fsp, /* result */
- NULL); /* pinfo */
-
- /* close fd from mkstemp() */
- close(tmpfd);
+ /* Create the file. */
+ status = SMB_VFS_CREATE_FILE(
+ conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ smb_fname, /* fname */
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
+ FILE_CREATE, /* create_disposition*/
+ 0, /* create_options */
+ fattr, /* file_attributes */
+ oplock_request, /* oplock_request */
+ 0, /* allocation_size */
+ 0, /* private_flags */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL); /* pinfo */
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ TALLOC_FREE(fname);
+ TALLOC_FREE(smb_fname);
+ continue;
+ }
- if (!NT_STATUS_IS_OK(status)) {
- if (open_was_deferred(req->sconn, req->mid)) {
- /* We have re-scheduled this call. */
+ if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->sconn, req->mid)) {
+ /* We have re-scheduled this call. */
+ goto out;
+ }
+ reply_openerror(req, status);
goto out;
}
- reply_openerror(req, status);
+
+ break;
+ }
+
+ if (i == 10) {
+ /* Collision after 10 times... */
+ reply_nterror(req, status);
goto out;
}
@@ -2552,6 +2562,7 @@ void reply_ctemp(struct smb_request *req)
fsp->fh->fd, (unsigned int)smb_fname->st.st_ex_mode));
out:
TALLOC_FREE(smb_fname);
+ TALLOC_FREE(wire_name);
END_PROFILE(SMBctemp);
return;
}