sunshine_august has asked for the wisdom of the Perl Monks concerning the following question:

hi, all monks:

I have writen a script under a normal user, like "larry", this script can generate some text files, and put these files into a directory owned by "nobody" user, but if I run the script under "larry" user, it can't put the files into the directory owned by "nodoby" user because of the permission.

So, is there any way to let the script generates the files owned by "nobody", and so can put them into the "nobody" directory? Just like Apache, the apache server is started by a root user, but run the cgi script under user "nobody".

  • Comment on How to run a perl script under "nobody" user?

Replies are listed 'Best First'.
Re: How to run a perl script under "nobody" user?
by moritz (Cardinal) on Nov 19, 2008 at 08:44 UTC
    You can use sudo to start a script under a different user (but you either need root powers, or sudo has to be configured to allow that).
      I try to do this, but faild:
      [root@localhost]# su - nobody -c "./foo.pl" This account is currently not available.
        That's not a perl problem anymore, I'll try anyway...

        Probably the user nobody has the program /usr/sbin/nologin as its login shell, which prints the message you have quoted and then exits.

        Possible solutions are (1) use sudo as I suggested, not su (2) convince su not to spawn a login shell (no - in the command line) or (3) give the user nobody a different login shell.

Re: How to run a perl script under "nobody" user?
by scorpio17 (Canon) on Nov 19, 2008 at 15:02 UTC
    Apache usually runs as the user 'nobody', although I've also seen it runs as 'www-user' on some systems. Either way, these are very low-privilege accounts, for security purposes. You don't want a buggy cgi script to clobber files in actual user directories. So if you have a cgi script that needs to write files, you'll need to create a directory that 'nobody' can write to. As root, you'd do something like this:
    mkdir mydata chown nobody:nobody mydata chmod 755 mydata
    But now, if you login as user 'larry', you won't have permission to modify those files (they're read only) If you're the web admin and need to, for example, delete them, what do you do? You have several options:
    • Write a cleanup script, and run it as a cgi script, too. You'll want this in a password protected area, so only the web admin can run it. It will do the cleanup then print an "all done" message. Since it will run as user 'nobody', it can modify, delete, etc. files owned by nobody. This works, but I don't really like this option.
    • You can create a suid script. This is a wrapper script that runs your cleanup script as some other user, in this case, 'nobody'. Sometimes admins create suid scripts for trusted users that allow them to do certain things as user 'root'. This saves them having to ask the admin to do it for them every time, and it's more secure than actually giving them a root login. But in general suid scripts are considered a potential security risk. In your case, you'd actually be demoting a regular user (larry) to a non-privileged user (nobody) - so I think your risk is minimal. But you'll need someone with root login to setup the suid script for you, initially.
    • You could also create a group, called, for example, web-admin. Then add users nobody and larry to the web-admin group. Then make sure that all the files nobody writes have group read/write permission (chmod 775). Then larry can edit nobody's files, because they are in the same group. If other people need access, just add them to the group. I like this solution the best. But you'll need root login to manage the group setup.
    • One last option: avoid file I/O completely, and use a database instead (like mysql or sqlite). A cgi script can use the DBI module to connect to the database and read/write, and then later 'larry' (or any other user) can connect using a database client tool and do whatever. You can handle read/write access within the database then, using, for example, the GRANT command in mysql.
    I hope this helps - good luck!