Why can I 'touch' a write-protected file? - linux

Why is it possible to touch a write-protected file?
Shouldn't the following give an error?
$ touch test.txt
$ chmod a-w test.txt
$ ls -l test.txt
-r--r--r-- 1 name group 0 Jun 13 09:14 test.txt
$ touch test.txt && echo OK
OK
$ ls -l test.txt
-r--r--r-- 1 name group 0 Jun 13 09:15 test.txt
Does touch change permissions, touch the file, and change permissions back? Why would it do that?
Given this behavior, if I really want to protect a file so that I (my user) will never (unintentionally) change, remove or change its timestamp in the future -- how can I do it?
(Sorry, not strictly programming-related, but slightly, and probably of interest to many programmers.)

From the touch (coreutils) documentation:
If changing both the access and
modification times to the current
time, `touch' can change the
timestamps for files that the user
running it does not own but has write
permission for. Otherwise, the user
must own the files.

The execution permissions of the directory that the file contains dictates the ability to delete or modify the inode information for the entry in the directory that is associated with the file.
As the comment below indicates I have glossed over the technical reason but instead offered a reasoning why the behavior might not be as expected. Since you can execute in the directory there are a number of things you can do to tinker with the file and I am going to leave it at that.
If you want to stop anyone but root from modifying a file the best method is to use the chattr +i filename on the file. Even root will not be able to perform any actions on it without running chattr -i on it. This applies to Linux so YMMV.

Here's the relevant output from : strace "touch test.txt"
open("test.txt", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0666) = -1 EACCES (Permission denied)
futimesat(AT_FDCWD, "test.txt", NULL) = 0
It indeed gets a "Permission denied error" on the open(2) system call regarding EACCES. See relevant section in utimes(2) man page.
However, it does succeed in updating the timestamp using the futimesat(2) system call.
As others have indicated, it looks like the directory permissions hold the rights to update access/moficiation timestamps.
You can, however change the attribute of a file to immutable using:
chattr +i test.txt
Note: Only root can do this, and it's a very harsh way to disable access to files. But in extreme cases, it can be useful. In addition, this is an ext2/3/4 feature, not available on other filesystems as far as I know.

You can update the modification time if you own the file, regardless of write permission. (It is not related to any permission on the directory.)
From POSIX.1-2008:
Only a process with the effective user ID equal to the user ID of the file, or with write access to the file, or with appropriate privileges may use futimens() or utimensat() with a null pointer as the times argument or with both tv_nsec fields set to the special value UTIME_NOW. Only a process with the effective user ID equal to the user ID of the file or with appropriate privileges may use futimens() or utimensat() with a non-null times argument that does not have both tv_nsec fields set to UTIME_NOW and does not have both tv_nsec fields set to UTIME_OMIT. If both tv_nsec fields are set to UTIME_OMIT, no ownership or permissions check shall be performed for the file, but other error conditions may still be detected (including [EACCES] errors related to the path prefix).

In layman's terms, using the touch command will update or create a file without editing/modifying its contents. Because the command doesn't(and can't) write or erase anything from the file, it can be used on write-protected files. See the wiki on the touch command for more information: http://en.wikipedia.org/wiki/Touch_(Unix)

Related

is there a way to force execute permission on all files that will be created under a specific directory?

So I was wondering if there's a way to add in a way to force all files being created in e.g. /tmp/test directory to always have execute permission?
I tried via the setfacl, but that one doesn't allow files to have execute permissions, it allows directories though strangely enough...
Any other ideas? I can try and do the obvious of making a cronjob or script that loops and just adds those permissions in that directory, but that's a bit ham-fisted and rough.
The files cannot be given execution permissions by default as it can cause a security concern.
Other permissions can be set using umask:
umask [-p] [-S] [mode]
The user file-creation mask is set to mode. If mode begins > with a digit, it is interpreted as an octal number; otherwise it is >interpreted as a symbolic mode mask
similar to that accepted by chmod(1). If mode is omitted, the >current value of the mask is printed. The -S option causes the mask to be >printed in symbolic form;
the default output is an octal number. If the -p option is >supplied, and mode is omitted, the output is in a form that may be reused as >input. The return status
is 0 if the mode was successfully changed or if no mode >argument was supplied, and false otherwise.
You will not be able to access (change to) a directory unless it is executable. Otherwise, a permission denied error will occur. I don't believe it is possible to make every file executable upon creation with setfacl.

Linux setuid bit [duplicate]

I created this simple script to allow the user to remove files created by the web server in his home directory without giving him "su". Both scripts are set with "chmod 4750".
The craziest thing is that they DID work and now they don't. Here's the scripts:
#!/bin/bash
# Ask for directory to delete
echo "Enter the file or directory you would like to delete, the assumed path is /home/user"
read DIRECTORY
rm -rf /home/user/"$DIRECTORY"
echo "Deleting /home/user/$DIRECTORY ..."
exit 0
2:
#!/bin/bash
# Reset permissions
echo "Resetting the ownership of the contents of /home/user to user."
chown -R user /home/user
exit 0
I will make them a little more advanced and work for multiple users but right now I cannot even get the simple version to work. It works when run as root of course. It used to work when run as user 'user' but now it doesn't. I get this:
user#dev:/home/user$ delete.sh
Enter the file or directory you would like to delete, the assumed path is /home/user/[your input]
test-dir
rm: cannot remove ‘/home/user/test-dir/test-file’: Permission denied
Deleting /home/user/test-dir ...
and
chown: changing ownership of ‘/home/user/test-dir’: Operation not permitted
What can possibly be the problem?
-rwsr-x--- 1 root user 291 Nov 6 05:23 delete.sh
-rwsr-x--- 1 root user 177 Nov 6 05:45 perms.sh
There is a pretty comprehansive answer at https://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts
Bottom line is that there are two main points against it:
A race condition between when the Kernel opens the file to find which interpreter it should execute and when the interpreter opens the file to read the script.
Shell scripts which execute many external programs without proper checks can be fooled into executing the wrong program (e.g. using malicious PATH), or expand variables in a broken way (e.g. having white space in variable values), and generally it has less control on how well the external programs it executes handle the input.
Historically, there was a famous bug in the original Bourne shell (at least on 4.2BSD, which is where I saw this in action) which allowed anyone to get interactive root shell by creating a symlink called -i to a suid shell script. That's possibly the original trigger for this being prohibited.
EDIT: To answer "How do I fix it" - configure sudo to allow users to execute only these scripts as user root, and perhaps use a trick like in https://stackoverflow.com/a/4598126/164137 to find the original user's name and force operation on their own home directory, instead of letting them pass in any arbitrary input (i.e. in their current state, nothing in the scripts you include in your question prevents user1 from executing the scripts and passing them users2's directory, or any directory for that matter)

Does root overrides read only permission(even to root) set to directory in unix?

I have created directory and set read only permission for root using chmod.
chmod -R 400 some_dir/
but when I try to create any file inside it using touch, I was expecting error message something like
touch some_dir/hello.txt
"touch: cannot touch `some_dir/hello.txt': Permission denied"
but it creates file "hello.txt" inside it happily, but directory permission if I check it still shows readonly for root. Please explain what I'm missing here, since I was expecting error message which would be displayed if any other user(apart from root) try to create file in that directory?
PS: I'm running as root user.
Short answer is - Yes, Root user can create files in a directory that is marked as Read Only. You may argue - why? But that's the whole point of root account. It's a special user and it can do things that others can't.
If you want to prevent the file from accidental modifications, you can set the i attribute of the file on with chattr +i command. This will make the file unchangeable. However, note that it will only prevent accidental modifications. Root users can still just unset the attribute first and then modify the file.

In Unix shell, how to Check user's permission ,if the user doesn't have, how to produce an error message?

I was trying to write a script which will be able to perform some build-in command ,such as : cp, rm, ls or whatever.
The menu might be like this:
list the current directory
Rename a file
Remove a file
exit
when you executed that some commands like "ls -la $currentdirectory"
which will show almost all the information of the current directory.
SO: if the user does not have permission to do that, (the user doesn't have permission to "LS" that directory .
what command can check the permission?
How to produce an error message if that user does not have the permission?
Cheers
hope to get that answer.
You don't need any separate command to figure out permissions on a directory/file. ls itself will output an error kinda message.
For example, I take away all permissions from everyone,
chmod 000 some_folder
ls some_folder/
ls: some_folder/: The file access permissions do not allow the specified action.
Most commands in Unix like systems will automatically error out with an error message if they don't have sufficient permissions to do their job! The underlying framework will take care of not allowing under-privileged users/apps to run.
grep -i umask ~/.profile /etc/profile

Bash: Permission denied when trying to open a file

I recently decided to try to learn some bash scripting and as a fun exercise I decided to make a script to open up a daily file for me to write notes in whenever the script is run.
It worked fine until I logged out and back in to the system later, when I received an error
/usr/local/bin/notes: line 45: /home/MY_USERNAME/notes/2010-10-01:Permission denied
Code
I might be mistaken, but this certainly doesn't seem like something that shouldn't require extra permissions, does it?
Editor is set to nano
File's permissions are -rw-rw-r--
Script's permissions are -rwxr-xr-x
check the permission on the file with
ls -l /path/to/your/file
you should see something like
-rw-r--r--
r mean readable, w writeable, and x executable.
the first set is for your user, the second set of three is for your group, and the third set is for anyone.
so in my example, the file i have shown is read/write for me, and read only for my group and for any other user.
Use the chmod command to change permissions.
chmod 744 file
will make the file read/write/exec for you, and just read for user/world.
My guess is that in
$EDITOR $DAILY_FILENAME
$EDITOR is null, so it's trying to execute $DAILY_FILENAME which not executable. Probably while you were testing you set EDITOR manually, but didn't add it to your .bashrc (or whatever) file.
Use the -x option to prove it.
If I had to guess, I would suggest that the $EDITOR environment variable is undefined for some reason. It looks like your script is attempting to execute the notes file - as this isn't executable you get the unhelpful error message.

Resources