Fix bug in old create temp SMB request. Only use VFS functions.
authorJeremy Allison <jra@samba.org>
Wed, 17 Apr 2013 21:42:20 +0000 (14:42 -0700)
committerDavid Disseldorp <ddiss@samba.org>
Sat, 20 Apr 2013 19:13:36 +0000 (21:13 +0200)
Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: David Disseldorp <ddiss@samba.org>
Autobuild-User(master): David Disseldorp <ddiss@samba.org>
Autobuild-Date(master): Sat Apr 20 21:13:36 CEST 2013 on sn-devel-104

source3/smbd/reply.c

index cff1aa74986533d96c718884bfb4f0b3ca09e315..8790bd5b91905099759a9b40d5f5e1d5c5c81485 100644 (file)
@@ -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;
 }