Crawlicious | tools for web business

TAG | shell scripting

Sep/09

1

Running as SetUID

So, I had this problem where I needed to be able to run an operation as another user. The operation was to kill a process for another user. Let’s say that you wanted to kill ‘apache’, but you were ‘bob’. People that I discussed this with had the first thought that we should just make a script that was setuid. Well, I know from experience that the shell does not allow that. So a second thought was to copy /bin/kill to a home directory and set the owner for that as apache. The problem is that /bin/kill does not want to take advantage of setuid bits and just ignores it. So, I had to write my own kill command.

The basic idea is to elevate your privileges to the owner of the file, perform the operation and then exit. Here is a code example of what APIs to use.

#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>

// we need the above includes to give us stat, the buffer type, and seteuid

// this is the structure to put the data from the file into
struct stat buff; 

// now, look at the executable file (argv[0]), dump the details into our buffer
if (stat(argv[0], &buff) == -1) {
        printf("error running stat on %s (trying to find out who we need to be)\n", argv[0]);
        exit(1);
}

// now attempt to elevate priveleges to the file owner
if (seteuid(buff.st_uid) == -1) {
    printf("error running setuid to %ld!\n", (long)buff.st_uid);
    exit(1);
}

// NOW RUN SOME API AS THAT OTHER USER

Of course, unless the executable is setuid to another user, then it won’t really do anything for you. To set the setuid bit on a file, simply use this shell command.

chown USER_TO_BE FILENAME
chmod a+s FILENAME

Well, have fun, and don’t hurt yourself. There is a reason that unix commands try to lower privileges as quickly as possible and don’t want to do things as other users.

, , , Hide

So, yesterday my boss had some unusual weirdness with a bash shell script that he was writing and together we were able to figure out what was going on. Here is a boiled down example of it.

He wanted to test that a file didn’t exist, and if so, perform some action. He wanted to use the ‘-a’ conditional test directive. Here is a little example.

if [ -a 'afile' ]; then echo "exists" ; else echo "not exists"; fi

when the file exists, it prints ‘exists’, and when it doesn’t exist, it prints ‘not exists’.

So far so good. Well, lets just switch things around a bit. He wanted the first condition to be the negative sense so we use the ! (bang) to not the results of ‘-a’.

if [ ! -a 'afile' ]; then echo "not exists"; else echo "exists"; fi

Well, this always prints ‘not exists’ regardless of the existence of the file. Now switch the operator to ‘-e’ (which is the operator that I use usually).

if [ ! -e 'afile' ]; then echo "not exists"; else echo "exists"; fi

Now things work as expected…

If you look up the man page for bash, you will see why my boss wanted to use ‘-a’, it is listed there as …

-a file
True if file exists.

And -e has an identical entry.

But, if you look up the man page for test, then you will see a different story.

EXPRESSION1 -a EXPRESSION2
both EXPRESSION1 and EXPRESSION2 are true

So, the question is, why is the ‘-a’ being processed by test instead of the shell? It is because in the if clause we are using ‘[' to initiate the test. '[' is actually the 'test' command (try running man [, or which [ ). Basically test was being asked if '!' is true and 'afile' is true, and they weren't.

So, use '-e' to eliminate that confusion, because '-e' means equal in both bash and test. Also, you could phrase it this way...

if ! [ -a 'afile' ]; then echo "not exists"; else echo "exists"; fi

i.e. put the bang outside of the test command.

There are many other ways that you could write this, but as you can see, for the sake of eliminating confusion, you should always prefer to use '-e' over '-a' when shell scripting.

Hide

Find it!

Theme Design by devolux.org