15cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// Copyright 2014 The Chromium OS Authors. All rights reserved. 25cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// Use of this source code is governed by a BSD-style license that can be 35cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// found in the LICENSE file. 45cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include "brillo/file_utils.h" 65cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 75cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell#include <fcntl.h> 85cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell#include <unistd.h> 95cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 105cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell#include <base/files/file_path.h> 115cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell#include <base/files/file_util.h> 125cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell#include <base/files/scoped_file.h> 135cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell#include <base/logging.h> 145cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell#include <base/posix/eintr_wrapper.h> 155cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 169ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo { 175cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 185cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellnamespace { 195cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 205cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellenum { 215cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell kPermissions600 = S_IRUSR | S_IWUSR, 225cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell kPermissions777 = S_IRWXU | S_IRWXG | S_IRWXO 235cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell}; 245cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 255cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// Verify that base file permission enums are compatible with S_Ixxx. If these 265cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// asserts ever fail, we'll need to ensure that users of these functions switch 275cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// away from using base permission enums and add a note to the function comments 285cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// indicating that base enums can not be used. 295cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_READ_BY_USER == S_IRUSR, 305cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 315cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_WRITE_BY_USER == S_IWUSR, 325cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 335cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_EXECUTE_BY_USER == S_IXUSR, 345cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 355cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_READ_BY_GROUP == S_IRGRP, 365cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 375cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_WRITE_BY_GROUP == S_IWGRP, 385cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 395cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_EXECUTE_BY_GROUP == S_IXGRP, 405cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 415cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_READ_BY_OTHERS == S_IROTH, 425cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 435cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_WRITE_BY_OTHERS == S_IWOTH, 445cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 455cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellstatic_assert(base::FILE_PERMISSION_EXECUTE_BY_OTHERS == S_IXOTH, 465cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell "base file permissions don't match unistd.h permissions"); 475cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 485cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellenum RegularFileOrDeleteResult { 495cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell kFailure = 0, // Failed to delete whatever was at the path. 505cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell kRegularFile = 1, // Regular file existed and was unchanged. 515cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell kEmpty = 2 // Anything that was at the path has been deleted. 525cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell}; 535cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 545cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// Checks if a regular file owned by |uid| and |gid| exists at |path|, otherwise 555cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// deletes anything that might be at |path|. Returns a RegularFileOrDeleteResult 565cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// enum indicating what is at |path| after the function finishes. 575cadeae88cd2ab9b4aebf6d880455df602001c90David PursellRegularFileOrDeleteResult RegularFileOrDelete(const base::FilePath& path, 585cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell uid_t uid, 595cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell gid_t gid) { 605cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // Check for symlinks by setting O_NOFOLLOW and checking for ELOOP. This lets 615cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // us use the safer fstat() instead of having to use lstat(). 625cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell base::ScopedFD scoped_fd(HANDLE_EINTR(openat( 635cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell AT_FDCWD, path.value().c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW))); 645cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell bool path_not_empty = (errno == ELOOP || scoped_fd != -1); 655cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 665cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // If there is a file/directory at |path|, see if it matches our criteria. 675cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (scoped_fd != -1) { 685cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell struct stat file_stat; 695cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (fstat(scoped_fd.get(), &file_stat) != -1 && 7005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko S_ISREG(file_stat.st_mode) && file_stat.st_uid == uid && 715cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell file_stat.st_gid == gid) { 725cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return kRegularFile; 735cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 745cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 755cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 765cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // If we get here and anything was at |path|, try to delete it so we can put 775cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // our file there. 785cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (path_not_empty) { 795cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (!base::DeleteFile(path, true)) { 805cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell PLOG(WARNING) << "Failed to delete entity at \"" << path.value() << '"'; 815cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return kFailure; 825cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 835cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 845cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 855cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return kEmpty; 865cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell} 875cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 885cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// Handles common touch functionality but also provides an optional |fd_out| 895cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// so that any further modifications to the file (e.g. permissions) can safely 905cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// use the fd rather than the path. |fd_out| will only be set if a new file 915cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// is created, otherwise it will be unchanged. 925cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// If |fd_out| is null, this function will close the file, otherwise it's 935cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell// expected that |fd_out| will close the file when it goes out of scope. 945cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellbool TouchFileInternal(const base::FilePath& path, 955cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell uid_t uid, 965cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell gid_t gid, 975cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell base::ScopedFD* fd_out) { 985cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell RegularFileOrDeleteResult result = RegularFileOrDelete(path, uid, gid); 995cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell switch (result) { 1005cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell case kFailure: 1015cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return false; 1025cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell case kRegularFile: 1035cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return true; 1045cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell case kEmpty: 1055cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell break; 1065cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 1075cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1085cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // base::CreateDirectory() returns true if the directory already existed. 1095cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (!base::CreateDirectory(path.DirName())) { 1105cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell PLOG(WARNING) << "Failed to create directory for \"" << path.value() << '"'; 1115cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return false; 1125cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 1135cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1145cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // Create the file as owner-only initially. 1155cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell base::ScopedFD scoped_fd( 1165cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell HANDLE_EINTR(openat(AT_FDCWD, 1175cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell path.value().c_str(), 1185cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell O_RDONLY | O_NOFOLLOW | O_CREAT | O_EXCL | O_CLOEXEC, 1195cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell kPermissions600))); 1205cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (scoped_fd == -1) { 1215cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell PLOG(WARNING) << "Failed to create file \"" << path.value() << '"'; 1225cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return false; 1235cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 1245cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1255cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (fd_out) { 1265cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell fd_out->swap(scoped_fd); 1275cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 1285cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return true; 1295cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell} 1305cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1315cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell} // namespace 1325cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1335cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellbool TouchFile(const base::FilePath& path, 1345cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell int new_file_permissions, 1355cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell uid_t uid, 1365cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell gid_t gid) { 1375cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // Make sure |permissions| doesn't have any out-of-range bits. 1385cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (new_file_permissions & ~kPermissions777) { 1395cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell LOG(WARNING) << "Illegal permissions: " << new_file_permissions; 1405cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return false; 1415cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 1425cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1435cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell base::ScopedFD scoped_fd; 1445cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (!TouchFileInternal(path, uid, gid, &scoped_fd)) { 1455cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return false; 1465cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 1475cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1485cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // scoped_fd is valid only if a new file was created. 1495cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell if (scoped_fd != -1 && 1505cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell HANDLE_EINTR(fchmod(scoped_fd.get(), new_file_permissions)) == -1) { 1515cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell PLOG(WARNING) << "Failed to set permissions for \"" << path.value() << '"'; 1525cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell base::DeleteFile(path, false); 1535cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return false; 1545cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell } 1555cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1565cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell return true; 1575cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell} 1585cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1595cadeae88cd2ab9b4aebf6d880455df602001c90David Pursellbool TouchFile(const base::FilePath& path) { 1605cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // Use TouchFile() instead of TouchFileInternal() to explicitly set 1615cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell // permissions to 600 in case umask is set strangely. 162bf74b6a523872c7aa73214e911201c28b13a786bDavid Pursell return TouchFile(path, kPermissions600, geteuid(), getegid()); 1635cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell} 1645cadeae88cd2ab9b4aebf6d880455df602001c90David Pursell 1659ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko} // namespace brillo 166