diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index 2e7c02b7850..12fcc3ac541 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -1148,9 +1148,13 @@ class AnsibleModule(object): if self.selinux_enabled(): self.set_context_if_different( tmp_dest.name, context, False) - tmp_stat = os.stat(tmp_dest.name) - if dest_stat and (tmp_stat.st_uid != dest_stat.st_uid or tmp_stat.st_gid != dest_stat.st_gid): - os.chown(tmp_dest.name, dest_stat.st_uid, dest_stat.st_gid) + try: + tmp_stat = os.stat(tmp_dest.name) + if dest_stat and (tmp_stat.st_uid != dest_stat.st_uid or tmp_stat.st_gid != dest_stat.st_gid): + os.chown(tmp_dest.name, dest_stat.st_uid, dest_stat.st_gid) + except OSError, e: + if e.errno != errno.EPERM: + raise os.rename(tmp_dest.name, dest) except (shutil.Error, OSError, IOError), e: self.cleanup(tmp_dest.name) diff --git a/test/integration/roles/test_copy/tasks/main.yml b/test/integration/roles/test_copy/tasks/main.yml index 9266a32685c..8c4892bea80 100644 --- a/test/integration/roles/test_copy/tasks/main.yml +++ b/test/integration/roles/test_copy/tasks/main.yml @@ -182,3 +182,28 @@ - "copy_result6.dest == '{{output_dir|expanduser}}/multiline.txt'" - "copy_result6.md5sum == '1627d51e7e607c92cf1a502bf0c6cce3'" +# test overwriting a file as an unprivileged user (pull request #8624) +# this can't be relative to {{output_dir}} as ~root usually has mode 700 + +- name: create world writable directory + file: dest=/tmp/worldwritable state=directory mode=0777 + +- name: create world writable file + copy: dest=/tmp/worldwritable/file.txt content="bar" mode=0666 + +- name: overwrite the file as user nobody + copy: dest=/tmp/worldwritable/file.txt content="baz" + sudo: yes + sudo_user: nobody + register: copy_result7 + +- name: assert the file was overwritten + assert: + that: + - "copy_result7.changed" + - "copy_result7.dest == '/tmp/worldwritable/file.txt'" + - "copy_result7.md5sum == '73feffa4b7f6bb68e44cf984c85f6e88'" + +- name: clean up + file: dest=/tmp/worldwritable state=absent +