diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/smbd/reply.c | 117 |
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; } |