diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c index 1ab9cac76f2f..42eb99e99355 100644 --- a/usr.bin/xinstall/xinstall.c +++ b/usr.bin/xinstall/xinstall.c @@ -824,6 +824,7 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags) int tempcopy, temp_fd, to_fd; char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN]; char *digestresult; + uid_t euid; digestresult = NULL; files_match = stripped = 0; @@ -886,7 +887,20 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags) if (docompare && !dostrip && target && S_ISREG(to_sb.st_mode)) { if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) err(EX_OSERR, "%s", to_name); - if (devnull) + /* + * Even if the contents are the same, we want to rename + * temp files when doing a "safe" copy if the + * permissions and ownership need to change. We may + * not have permission to chown/chmod the "to" file + * directly. + */ + if (tempcopy && (euid = geteuid()) != 0 && + euid != to_sb.st_uid && + ((gid != (gid_t)-1 && gid != to_sb.st_gid) || + (uid != (uid_t)-1 && uid != to_sb.st_uid) || + (mode != (to_sb.st_mode & ALLPERMS)))) + files_match = 0; + else if (devnull) files_match = to_sb.st_size == 0; else files_match = !(compare(from_fd, from_name,