Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I am creating a utility which will run on Linux machines. For the purposes of this discussion, let's say its analogous to make.

Here's the deal : sometimes, when you run the utility, it creates files in the directory you're running in, and these need to be created as the same user/group as the user executing the tool. This is the "make main.o" scenario - create main.o from main.c. This will be the default when you run the utility as your own user, which is fine.

Sometimes, when you run the utility, it creates files in /usr/local/bin and such, which need to be root:root. This is the "sudo make install" scenario - create /usr/local/bin/executable under root:root. This will be the default when you run the utility as root, which is fine.

The problem is, that in all cases, the utility needs to manage some additional cache files, say in /var/cache/utility. When you run the utility as root, these files are root:root, which is a problem the next time you run the utility as your normal user. They can't be deleted/modified.

What I am wondering is, is it a good idea to create a dedicated user/group for this utility when you install it? I know apache, svn, and others do this. This is the only approach I can think of, but I am open to other solutions.

If I DO have a dedicated user/group for the utility, how do I temporarily assume the identity of that user for the purposes of managing the cache files, and then resume the previous identity for the remainder of execution (for creating regular files as user:user, and system files as root:root) ?

What I've got so far is something like this:

  • getpwnam(predefined_utility_user_name) // get the uid
  • seteuid(utility_uid)
  • setegid(utility_gid)

// do stuff in /var/cache/utility

  • seteuid(getuid()) // resume previous id
  • setegid(getgid()) // resume previous group

THE PROBLEM : assuming the predefined_identity does NOT work when running the utility as yourself! It works when you run as root (obviously).

I am fine adding myself and other users to the group associated with the utility. However, that does not work. So - how do I make that work? Is this a bad idea?

EDIT : Response to below suggestion

I've done some more reading and I think I have a good solution using #2 you've suggested it looks like this

The executable of the utility is owned by utility:utility and has both u+s and g+s permissions. Therefore, right when I start executing, I have euid/egid of utility, and utility, respectively. I have ruid/rgid of whichever user executed the program. So, what I can do is, when I start executing, setegid(getgid()) and seteuid(getuid()). This allows the process to assume the identity of whoever executed the program. I will maintain this for the entire duration of the program, EXCEPT while dealing with /var/cache/utility, I use the same technique to assume the utility:utility identity.

I don't need to partition the software, there is no group to which your user must belong, the executable just needs its own user/group and u+s and g+s. I guess you have to trust that the program is not malicious, but you have to assume that anyway if you're going to execute it. Thoughts?

share|improve this question
    
Hi Todd. That sounds like a good solution. I think the security isn't a problem, because when a user invokes the utility it receives all their access anyway. –  Kevin A. Naudé Dec 24 '12 at 19:22

1 Answer 1

For clarity, the problem with your code is that unprivileged users can only seteuid in a few cases based on how the executable was invoked. So we need another solution.

This is an interesting problem. There are different ways you could solve it. I don't know if there is an accepted best-practice solution, but here are some options.

  1. Set sticky-group permissions on /var/cache/utility.

    This approach allows your utility to run under the initiators permissions. Make sure the user is in the group that owns /var/cache/utility, and change the permissions so that the group assignment is sticky for all contents. You can accomplish that with the following:

    mkdir /var/cache/utility
    chown -R :user /var/cache/utility
    chmod 2770 /var/cache/utility
    usermod -a -G users joe
    

    Now, since joe is in the users, when he runs your utility everything is ok. The group premission of any modified files in /var/cache/utility will remain users. The problem is that there is no group to which all users automatically belong. So this method won't automatically work for all users. There is also the security problem. You utility might modify files in /var/cache/utility in a well-behaved way, but this methods opens up the flood-gates to the wild west of userland.

  2. Split your utility into front- and back-ends.

    Dividing the utility into front- and back-ends is inconvenient, but does force you to formalise the operational interface. The communication between the parts can take two common forms:

    • Socket comms, whether unix sockets or TCP sockets. This requires that your back-end be a service.

    • Command-line tools. This is considerably simpler that using sockets, and your back-end does not run continuously.

    The idea is to uid-execute-sticky-bit on your back-end, so that it automatically runs under the owner's account, regardless of the current logged-in user. The front-end will still run under the credentials of the user.

    See if you can split your utility so that all manipulation of the cache is performed by the backend, but other activities are performed in the front-end. You can set the uid of the back-end as follows:

    chmod u+s /usr/bin/utility-back-end
    

    There is a reasonably good overview of this technique here. It is still somewhat inconvenient to partition the software like this, but it is the best solution I know. The following command will list all the utilities on your system that already use this method:

    find / -xdev \( -perm -4000 \) -type f -print0 | xargs -0 ls -l
    

Hope that helps.

share|improve this answer
    
/etc/passwd is world-readable (otherwise tools like ls couldn't map numerical uid/gid values to the proper user or group names). /etc/shadow has restricted readability, because it contains the encrypted passwords when the system is running with shadow passwords. –  Michael Kjörling Dec 24 '12 at 12:54
    
@MichaelKjörling Thanks, Michael. I've corrected the text accordingly. The problem is mostly associated with the restrictions that apply to seteuid and setegid. –  Kevin A. Naudé Dec 24 '12 at 13:04
    
Thanks alot for your ideas. See above for my response .. too long for comment field. –  Todd Freed Dec 24 '12 at 17:39

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.