This is a repost after being referred to "Calling a script from a setuid root C program - script does not run as root" for a solution
My problem is different in that I do not want to run the C program (and c-shell script called inside) as root. Rather, I want to run as the owner of the c program file.
Also, I tried with "setuid(0)" as this was the solution in the referenced post. This is reflected in the edited code below. Same results.
Also, I opened permissions up all the way this time with "chmod 7775" (just in case it was a permissions problem)
Here's the original note with edits to reflect the change to "setuid(0)"
I'm having a problem implementing an simple example that would demonstrate how setuid can be made to run a binary with the uid of the file owner of the binary. What I would eventually like to do is run a c-shell script using this technique.
I read that this will not work for shell scripts but also heard of a work-around using a C program to run a system() call that'll run the c-shell script ( e.g. system("source my.csh") ). I wrote a C program that attempts this, plus simply reports the current uid. This is what I tried...
From my current shell, I did a "su katman" to become the user of the binary I want to run as user katman.
I created a C program try.c. ...
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
setuid(0);
printf("In try.c ... sourcing katwhoami.csh...\n");
system( "source /home/me/su_experiments/katwhoami.csh");
printf("In try.c ... using straight system call...\n");
system("whoami");
return 0;
}
I "setuid(0)" as recommended by a reference to a different note. But earlier, I tried setting it to the uid of the C program's owner as obtained with "id -u".
The katwhoami.csh shell script is simply...
date
echo "In katwhoami.csh, I am "`whoami`
echo "In katwhoami.csh, I am "$USER
exit
Then I compiled the C program and set the bit...
% gcc -o try try.c
% chmod 7775 try
% ls -l try
-rwsrwsr-x 1 katman design 6784 Mar 1 11:59 try
And then I test it...
% try
In try.c ... sourcing katwhoami.csh...
Thu Mar 1 12:28:28 EST 2018
In katwhoami.csh, I am ktadmin
In katwhoami.csh, I am ktadmin
In try.c ... using straight system call...
ktadmin
...which is what I expected.
I exit to get back to the shell I started from, hoping that if I run try there, it'll tell me I'm "katman"....
% exit
% whoami
daveg
% try
In try.c ... sourcing katwhoami.csh...
Thu Mar 1 12:30:04 EST 2018
In katwhoami.csh, I am daveg
In katwhoami.csh, I am daveg
In try.c ... using straight system call...
daveg
... which is not what I was hoping for :-(
As you can probably tell, I'm new at using this.
Any help would be appreciated !
Update....
I tried a new sample program, a.c...
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fh;
setuid(1234);
system("whoami");
fh=fopen("test.file","w");
fprintf(fh,"Here I am\n");
fclose(fh);
return 0;
}
I compiled and set the bit
gcc -o a a.c
chmod 4775 a
Then I exited the "su" and ran as a user that is NOT the owner of the binary. Same result as before with regard to reported uid (the current uid), BUT, the owner of the file that the C program created ion this version was the owner of the C program !!! So that worked.
Is there something fishy about the "whoami" command? system() call ?
If I do a "system("source some.csh") does it create a new shell which assumes the original uid (not the owner of the C binary) ? Something like that ?
I really need the new uid to "stick" as far as child processes.
Related
I'm having trouble running some C code before launching an app from Spotlight or the Applications folder. I figured I should just be able to create an executable with my code where after all the computations are done I make a execvp() call to run the original app's executable, which will then replace the current process.
I compiled the .c file and gave it the original app's executable name (in my case clion) and then executed it from Terminal.. great, it works!.. Until I tried to open the app bundle from spotlight (or Finder)
For some reason the execvp() call fails and the original program continues, but my custom executable is indeed called by spotlight! Not even making a child process with fork() will work, neither a system() call. What could be the problem here?
Contents folder of CLion: clion is my executable, clion-real is the original executable
-rwxr-xr-x 1 marc admin 8700 22 Mai 10:35 clion
-rw-r--r-- 1 marc admin 550 22 Mai 10:35 clion-fake.c
-rwxr-xr-x# 1 marc admin 128353 21 Mai 12:56 clion-real
clion-fake.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char** argv) {
system("say 'called'");
char* args[] = {"./clion-real", NULL};
int status = execvp(args[0], args);
system("say 'failed'");
return 0;
}
When calling ./clion from terminal it works as intended, the system says called and the app opens, but when opening the .app from Spotlight it says both called and failed, which means that the execvp() call failed.
Errno 2 is ENOENT, aka "no such file or directory".
You need to make sure that the current working directoy for the execution of your clion binary is actually set to the directory where your binaries live in, otherwise relative paths like ./clion-real won't work.
I'm trying something very simple with setuid followed by getuid in a C program that is not working unless the user is the owner of the c program. I am setting the permissions bit using chmod 7777 in addition to thesetuid. Here is the C program...
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x;
printf("Setting uid to 1111\n");
x=setuid(1111);
printf("setuid returned... %d\n",x);
printf("Testing state of uid using getuid()\n");
printf("uid: %d\n",getuid());
return 0;
}
Given that 1111 is the uid of the owner of the C program (returned by id -u).
after gcc, chmod 7777 on the binary produced.
Testing as the owner works fine...
% suid
Setting uid to 1111
setuid returned... 0
Testing state of uid using getuid()
uid: 1112
and to check the permissions on the binary...
ls -l suid
-rwsrwsrwx 1 katman design 6852 Mar 1 17:56 suid
Then I become another user (same group BTW) and run the "suid" executable again...
% suid
Setting uid to 1111
setuid returned... 0
Testing state of uid using getuid()
uid: 57849
Why isn't setuid working given that the owner granted permission to do this?
Also...
Q: If I can get this to work, I have heard that one can do a system() call to run a cshell script from a C program like this and the shell script should run as the owner of the C program. The uid is "passed down" to children. True or False?
Q: If the cshell script runs a perl script which in turn runs system calls, etc... will all these offspring shells run as the owner of the parent C binary that started started the whole cascade? IOW, is the uid "inherited" by children?
I have this C file:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("%s\n", getlogin());
printf("%i\n", getuid());
}
I compile it, set the UID and GID both to root and set the setuid bit, so that it looks like this:
-rwsrwsr-x 1 root root 8735 Apr 8 19:51 a.out
However when I call $ ./a.out I still get:
user
1000
What am I doing wrong?
The real user ID is still the user that called the program, but the effective user ID is root. In a setuid program, they are not the same.
To get the effective user ID, call geteuid(). You can also use cuserid() to get the name associated with the effective user ID.
Your program has got only the permission to change its uid. To actually switch to root you have to call setuid(0) in it.
Please have a look here
... I'm new to C programming on Ubuntu, so please bear with me if i'm being too much of a noob.
I have a C file that when compiled, is allocated to a particular user (testUser) and is run as they log in as their shell. The user doesn't have sudo rights to the system in question. Basically this shell permits the user to update a file (/var/wwww/testfile) upon login and then reboots the system. Of course, it's the reboot which is giving me some issues, as they don't have superuser rights.
//file: testShell.c
#include <unistd.h>
//#include <linux/reboot.h>
int main(void)
{
execl("/usr/bin/nano", "nano", "/var/www/testfile", NULL);
execl("/usr/bin/shutdown", "shutdown", "-h 0", NULL);
//reboot(LINUX_REBOOT_CMD_RESTART);
return 0;
}
The file compiles just fine to testShell
I chown root:root testShell
Grant SetUID using chmod u+s testShell
Copy the file cp testShell /bin
Update the users account to use the shell chsh -s /bin/testShell testUser
I've read the man pages on shutdown and tried within the program itself using reboot (you can see in this particular version of the file, I've commented out the header file and call) but I still can't get this user to be able to reboot the system (Ubuntu 12.04 presently). I've even tried the "init 6" system call that was posted here, but all to no avail. I've also read that using the system() call isn't a particularly good idea: I've tried it none-the-less and still no joy.
It was my understanding that if I allocate the permissions correctly and then SetUID the file, anyone running that file would implicitly be running it under the owners rights, root in this case. In fact, the /var/www/testfile that the testUser is updating, is owned by root, so something's working correctly.
Any ideas where I'm going wrong?
It is really simple : you use directly execl to start nano and ... never return from it if it correctly works !
You should use a fork - exec- wait.
You will find a complete example on this other post from SO https://stackoverflow.com/a/19099707/3545273
I have a .c file compiled and would like to run via a cron job but I end up getting this error:
/bin/sh: /usr/local/bin/get1Receive.c: Permission denied.
What is causing this error and how do I fix it?
Should I be running the .c file in cron or a different compiled file?
Results from /tmp/myvars
GROUPS=()
HOME=/root
HOSTNAME=capture
HOSTTYPE=x86_64
IFS='
'
LOGNAME=root
MACHTYPE=x86_64-redhat-linux-gnu
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/usr/bin:/bin
POSIXLY_CORRECT=y
PPID=11086
PS4='+ '
PWD=/root
SHELL=/bin/sh
SHELLOPTS=braceexpand:hashall:interactive-comments:posix
SHLVL=1
TERM=dumb
UID=0
USER=root
_=/bin/sh
Results from file get1Receive.c
file get1Receive.c
get1Receive.c: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
Snippet of codes.
sprintf(queryBuf1,"SELECT ipDest, macDest,portDest, sum(totalBits) FROM dataReceive WHERE timeStampID between '%s' And '%s' GROUP BY ipDest, macDest, portDest ",buff1,buff2);
printf("\nQuery receive %s",queryBuf1);
if(mysql_query(localConn, queryBuf1))
{
//fprintf(stderr, "%s\n", mysql_error(localConn));
printf("Error in first query of select %s\n",mysql_error(localConn));
exit(1);
}
localRes1 = mysql_store_result(localConn);
int num_fields = mysql_num_fields(localRes1);
printf("\nNumf of fields : %d",num_fields);
printf("\nNof of row : %lu",mysql_num_rows(localRes1));
If the output of this command:
file get1Receive1.c
shows that file name to be a valid executable that part is very unusual, but okay.
Assuming you are using biz14 (or your real username's ) crontab try this:
use the command crontab -e to create this line in your crontab:
* * * * * set > /tmp/myvars
Wait a few minutes, go back into crontab -e and delete that entry.
Use the set command from the command line to see what variables and aliases exist.
Compare that with that you see in /tmp/myvars You have to change how your C code executes by changing the variables and aliases the cron job runs with.
If you are running the cron job in someone else's crontab, then you have a bigger problem. Check file permissions on get1Receive1.c. and the directory it lives in. That other user (the one who wons the crontab) has to have permissions set on your directory and get1Receive1.c so the job can run.
Example crontab entry:
0 10 * * 1-5 /path/to/get1Receive1.c > /tmp/outputfile
Read /tmp/outputfile to see what you got. You are using printf in your code. printf only writes to the controlling terminal. There is no controlling terminal, so redirect the printf stuff to a file.
Last effort on this problem:
Check return codes on EVERYTHING. All C functions like fread(), any db function, etc. If a return code gives a fail response ( these are different for different function calls) then report the error number the line number and function - gcc provides LINE and func. Example:
printf("error on line %d in my code %s, error message =%s\n", __LINE__, __func__, [string of error message]);
If you do not check return codes you are writing very poor C code.
CHECK return codes, please, now!
Permission wise you could have two issues.
1. The 'c' file's permissions don't allow who you are running it as to run it.
2. You are running the cron with a script which doesn't have permissions.
Here's a helpful post: How to give permission for the cron job file?
The fact that you are running a 'c' file and referring to it as a script makes me think you're using C shell and not writing it as a C language program which would need to be compiled and have the generated executable run by the cron. If you're not using gcc or have never called gcc on your 'C' script then it's not C and call it C shell to avoid confusion.