Qmail/popuser Environment Permissions (Linux/CentOS) - linux

I am trying to get a mail-receiving script working, but I am getting a permissions error when it tries to copy files to where I need them.
We're running a Linux/CentOS/Plesk webserver. I have qmail set to pipe messages that a certain address receives to a shell script. That script is supposed to write the messages to a file and copy them to one of the server's vhost subscriptions so that they can be accessed by code running via the webserver.
I can get the messages passed to the shell script no problem, and it can successfully write the received message to a file in the local directory (the recipient's folder in /var/qmail/mailnames/). When the script tries to copy the message file to the correct vhost directory, however, I get a 'permission denied' error.
--
.qmail (file piping mail to parse_mail.sh - included for clarity, this part is working as intended):
| true
| /bin/bash parse_mail.sh &> parse_mail_sh.log
--
parse_mail.sh:
echo "Start parse_mail $(date)";
u=$(/bin/id -u -n);
echo "running as ${u}";
umask 000;
# random tag name
templ='message';
rand=$(awk -vmin=100000000 -vmax=999999999 'BEGIN{srand(); print
int(min+rand()*(max-min+1))}');
tag=$templ$rand;
echo "Create dir ${tag}/";
/bin/mkdir $tag;
echo "Write message into ${tag}/";
/bin/cp /dev/stdin ${tag}/message.txt;
echo "Copy message to message_files/";
/bin/cp ${tag}/message.txt /var/www/vhosts/subscription/httpdocs/subfolder/message_files/${tag}_content.txt
echo "Remove ${tag}/";
/bin/rm -R ${tag};
echo "End parse_mail";
--
parse_mail_sh.log log shows:
Start parse_mail Thu Jul 18 11:07:06 EDT 2019
running as popuser
Create dir message494556566/
Write message into message494556566/
Copy message to message_files/
/bin/cp: failed to access '/var/www/vhosts/subscription/httpdocs/subfolder/message_files/message494556566_content.txt': Permission denied
Remove message494556566/
End parse_mail
--
Pretty straight-forward, right? 'popuser' just doesn't have permission to write to this other directory.
Except, here's the odd thing:
I'm not an expert, but I generally understand how unix/linux permissions work. I believe popuser DOES have the requisite permissions to access and write to the directory - the intervening directory structure is traversable, and I've added popuser to the groups necessary to write to that specific subscription folder.
I can su to popuser in the terminal and cd up and down the directory structure, and copy/create files in the correct places. I can even run the mail-receiving script from the terminal AS popuser, and it works perfectly. It only throws the error when triggered on receiving mail.
I assume this means that there is some difference in the environment popuser is operating in via qmail as opposed to the terminal - I just haven't been able to track down exactly what that might be (or find articles online about it).
Or perhaps I misunderstanding how something works? Like I said, not an expert...
So my question is:
Why can't the parse_mail.sh script successfully copy the created file to the indicated message_files/ directory when a message is received by qmail, given that that same script CAN do so when executed by the same system user (popuser) when run via the terminal?

After several days of fighting with this, I discovered the problem.
I had made all of the correct changes, but the system hadn't caught up.
I had restarted various services in PLESK - including the "POP/mail server"- but apparently postfix is not something you can control from there.
When I stopped and then restarted Postfix, my script suddenly worked.
My only theory is that perhaps 'popuser' was operating through postfix on an old session that didn't have my user group changes - which might explain why I could perform the operations via a popuser terminal, but the mail processor could not.

Related

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)

Using mkdir in my bash script and getting permission denied

i have script that is owned by root in a directory owned by root. part of the script is to make a directory that will hold the inputs/outputs of that script. i also have a sim link to that script so any user can run it from anywhere. i don't use the temp directory so this info can be used as logs later.
Problem: when a user tries to run the script they get an error that the directory cannot be created because of permission denied.
Questions: why won't the script make the directory so root owns it independent of what user runs it? how can the script make the directory so root owns it instead of the user that ran it? only the script needs this info, not the user.
Additional info:
the directory is: drws--s--x.
the script is: -rwxr-xr-x.
(if you need to know) the line in the script is simply: mkdir $tempdirname
i am matching the permissions of other scripts on the same server that output text files correctly, but since mine is a directory i'm getting permission errors.
i have tried adding the permissions for suid and sgid. suid sounded like the correct solution since it should make the script run as if it were run by the user that owns the script. (why isn't this the correct solution?)
i would like any user to be able to type in the sim link name, that will run the script that is owned by root in the directory that is owned by root, and the directories created by that script will stay in its own directory. and the end user has no knowledge or access to the inner workings of this process. (hence owned by root)
Scripts run as the user that runs them; the owner of the file and/or the directory it's in are irrelevant (except that the user needs read and execute permission to the file and directory). Binary executables can have their setuid bit set to make them always run as the file's owner. Old unixes allowed this for scripts as well but this caused a security hole, so setuid is ignored on scripts in modern unixes/Linuxes.
If you need to let regular users run a script as root, there are a couple of other ways to do this. One is to add the script to your /etc/sudoers file, so that users can use sudo to run it as root. WARNING: if you mess up your /etc/sudoers file, it can be hard to recover access to clean it up and get back to normal. Make a backup first, don't edit it with anything except visudo, and I recommend having a root shell open so if something goes wrong you'll have the root access you need to fix it without having to promote via sudo. The line you'll need to add will be something like this:
%everyone ALL=NOPASSWD: /path/to/script
If you want to make this automatic, so that users don't have to explicitly use sudo to run the script, you can start the script like this:
#!/bin/bash
if [[ $EUID -ne 0 ]];
then
exec sudo "$BASH_SOURCE" "$#"
fi
EDIT: A simpler version occurred to me; rather than having the script re-run itself under sudo, just replace the symlink with a stub script like this:
#!/bin/bash
exec sudo /path/to/real/script "$#"
Note that with this option, the /etc/sudoers entry must refer to the real script's path, not that of the symlink. Also, if the script doesn't take arguments, you can leave the "$#" off. Or use it, it won't do any harm either.
If messing with /etc/sudoers sounds too scary, there's another option: you could "compile" the script with shc (which actually just makes a binary executable wrapper around it), and make that setuid root (chmod 4755 /path/to/compiled-script; chown root /path/to/compiled-script). Since it's in a binary wrapper, setuid will work.

Owner cannot create file in folder with all permission Linux

I'm trying to create few files under folder with script, but not able to.
following is the folder privilege under which some files are to be created
su pnaid
The partial script content, responsible to create folder and create files in it
MKDIR_CMD="/bin/mkdir -p \"${PATH_TO_WRITE}\" > /dev/null 2>&1"
"${MKDIR_CMD}"
echo "Checking Dir Path exist"
if [ -d "${PATH_TO_WRITE}" ]; then
echo "Calling another script to create files under this folder"
"/createFiles.sh \"${PATH_TO_WRITE}\""
else
echo "WARNING: unable to create folder"
The parent folder to the $(PATH_TO_WRITE) has following privileges
drwxr-x---. 2 pnaid pnaid 4096 Dec 3 12:31 work_directory
Each time the statement "WARNING: unable to create folder" is displayed.
I tried creating a folder with pnaid user having 777 permission and feeding that in script instead of "${MKDIR_CMD}", in that case the statement "Calling another script to create files under this folder" is displayed but the other script is not able to write to this folder.
Also the echo statements from createFiles.sh when called from original script are not displayed, is there any way to view it.
If we perform the same commands on shell prompt instead of script, the commands work and desired output is obtained; i.e. folder is created with all the files in it.
Also the same script works if we run it with user root.
I believe this should work across Linux flavors, in this case I'm using CentOS
Please help me resolve this issue and let me know if I have missed mentioning any details.
Thanks
This line:
"${MKDIR_CMD}"
will not work. It treats the entire value of $MKDIR_COMMAND as the name of the program to run, it doesn't split it into the program and arguments, because you put quotes around it. Also, redirections are not processed when expanding a variable.
You need to use eval to re-parse the string:
eval "$MKDIR_CMD"
You have the same problem with:
"/createFiles.sh \"${PATH_TO_WRITE}\""
This should be:
/createFiles.sh "$PATH_TO_WRITE"
These problems don't depend on permissions, I doubt the script really works when run as root.
Here's a related question that shows how to store command parameters best in variables:
Setting an argument with bash
However, the solution there (using an array instead of a string) won't work if you're also storing shell operators like redirection.

mv command moves file but reports error: cannot stat no such file or directory

I am hoping that a more experienced set of eyes will find something obvious that I am missing or will be able to help me work around the errors that mv and rsync are producing. Up for the challenge?
Basic idea:
I have a bash script in which I am automating the move of files from one directory to another.
The problem:
When I run the script, periodically I get the following error from the mv command:
mv: cannot stat `/shares/directory with spaces/test file.txt': No such file or directory. The error code from the vm command is 1. Even more odd, the file move actually succeeds sometimes.
In addition, I have a branch of logic in the script that will alternately use rsync to move/copy specific files (from the same local file system source and destination as the mv command mentioned above). I get a similar error related to the stat() system call:
rsync: link_stat "/shares/directory with spaces/test file.txt" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1070) [sender=3.0.9]
This error does not always manifest itself when the script is run. Sometimes it completes the file move without complaint, while other times it will return the error consistently when the script is run successive times.
There is one additional ingredient you should be aware of (and I am growing to suspect this as a key ingredient in my grief): the directory /shares/ is a directory that is being monitored by an installation of Dropbox -- meaning it is watched and mirrored by an installation of Dropbox. At this point, I am unable to determine if dropboxd is somehow locking the file, or the like, such that it cannot be stat-ed. To be clear, the files are eventually freed from this state without further intervention and are mv-able.
The code:
mv -v --no-clobber "${SOURCEPATH}${item}" "${DESTINATIONPATH}${item}"
More info:
The following might, or might not, be relevant:
mount indicates the filesystem is ext4
Presumably, ownership and permissions shouldn't be an issue as the script is being run by root. Especially if the file system is not fuse-based.
The base "directory" in the path (e.g. /shares/) is a symlink to another directory on the same file system.
The flavor of Linux is Debian.
Troubleshooting:
In trying to eliminate any issues with the variable expansion or their contents, I tried hardwiring the bash script like such:
mv -v --no-clobber "/shares/directory with spaces/test file.txt" "/new destination/directory with spaces/test file.txt" after verifying via ls -al that "test file.txt" existed. For reference the permissions were: -rw-r--r--
Unfortunately, this too results in the same error.
Other possible issues I could think of and what I have done to try to rule them out:
>> possible issue: slow HDD (or drive is in low power mode) or external USB drive
>> findings: The drives are all local SATA disks set to not park heads. In addition, even when forcing a consistent read from the file system, the same error happens
>> possible issue: non-Linux, NFS or fuse-based file system
>> findings: nope, source and destination are on the same local file system and mount indicates the file system is ext4
>> possible issue: white space or other unprintable chars in the file path
>> findings: verified that the source and destination paths where properly wrapped in quotes
>> possible issue: continuation issues after escaped newline (space after \ in wrapped command)
>> findings: made sure the command was all on one line, still the same error
>> possible issue: globbing (use of * in specifying the files to move)
>> findings: nope, each file is specified directly by path and name
>> possible issue: path confusion from the use of local path
>> findings: nope, file paths are fully qualified starting from /
>> possible issue: the files are not actually in the path specified
>> findings: nope, verified the file existed right prior to executing the script via ls -al
>> possible issue: somehow the --no-clobber of mv was causing issues
>> findings: nope, tried it without, same error
>> possible issue: only files created via Dropbox sync to the file system are problematic
>> findings: nope, created a local file directly via touch new-local-file.txt and it too produced the same stat() error
My analysis:
The fact that mv and rsync produce similar stat() errors leads me to believe:
there is some systemic underlying boundary case (e.g. file permissions/ownership or file busy) that is not accounted for in the bash script; or
the same bug is plaguing me in both the mv and the rsync scenarios.
Desired outcomes:
1. The root cause of the intermittent errors can be identified.
2. The root cause can be resolved or worked around.
3. The bash script can be improved to gracefully handle when the error occurs.
So, with a lot more troubleshooting I found an errant rsync statement some 200 lines earlier in the script that was conditionally executed (thus the seeming inconsistent behavior). That rsync --archive ... statement was being passed /shares/ as its source directory, therefore it effected the /shares/directory with spaces/ subdirectory. That subdirectory was the ${SOURCEPATH} of the troubling mv command mentioned in my post above.
Ultimately, it was a missing --dry-run flag on the rsync --archive ... statement that causing the trampling of the files that the script later expected to pass to mv to process.
Thanks for all who took the time to read my post. Though I am bummed to have spent my and your time on what turned out to be a bug in my script, it is reassuring to know that:
- computers are not irrational
- I am not insane
- there is not some nefarious, deep rooted bug in the linux file system
For those that stumble upon this post in the future because you are experiencing an error of cannot stat, please read my troubleshooting notes above. Much research went into that list. One of those might be your issue. If not, keep debugging, there is an explanation. Good luck!

App with access to directories outside the SandBox. Root access

I'm creating an app for the iPhone (Jailbreak). Said app modifies this directory (among others) "/Ringtones.PQNYRJ/", trying to create a ringtone file. The thing is that I've tried it every possible way and I can't get it to work. I've followed the Cydia's documentation and I've made a file with the same name as the app but with a shell script to execute the binary (renamed with an underscore).
dir=$(dirname "$0")
exec "${dir}"/MyTones_ "$#" 2>>/tmp/MyTones.log
I've set the proper permissions (or so I think)... I've based them off of Cydia.app permissions and all I got back is:
AVAssetExportSessionStatusFailed:
Error Domain=NSURLErrorDomain
Code=-3000 "Cannot create file"
UserInfo=0xa79750
{NSUnderlyingError=0xa79860 "The
operation couldn’t be completed.
(OSStatus error -12115.)",
NSLocalizedDescription=Cannot create
file}
Any suggestion?
I don't about the error, but i'll just list everything i did, successfully.
chmod the run script to 755 (obvious)
chmod the app binary to 4755 and chown to 0:0 (root)
Setup the Info.plist to launch the run script, not app binary (again, obvious)
Try changing your script to just: (log file not strictly necessary)
dir=$(dirname "$0")
exec "${dir}"/AppBinary
That's everything i did, and it works perfectly.
Of course, we're talking Jailbroken here, Apple would never allow this in the AppStore.

Resources