I just created C program that require a root to privileges run properly. I want to execute it using special keybindings in my regular user account, so is there any way that I can give the program root permission and execute it with my regular user without typing sudo?? I already tried to change the owner ship to the root user and adding s mode to the user but it didn't help. Any ideas?? Here is the code:
/*
*This program will make some cleaning that i regularly do,
*before the full system backup. And then itll create new dir
*in my HDD with date to make the system backup in it useng rsync.
*The program will use system() to connect all the command line tools
*together and automate this process.
*/
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#define DEV_PATH "/run/media/yan/HDD/"
void delete_dir(char *);
void get_date(int *);
char *make_backup_dir(const char *, int *);
void backup_sys(char *);
int main() {
char *dirs_to_clean[] = {
"/home/yan/.cache/spotify", "/home/yan/.cache/yay/*",
"/home/yan/.cache/mozilla/firefox/9jizeht4.default-release/cache2", "\0"
};
char *backup_path_ptr;
int date[3]; //Array for the date of today
int i;
//System cleaning
for(i=0; *dirs_to_clean[i]!='\0'; i++) //Delete every dir in the dirs_to_clean array
delete_dir(dirs_to_clean[i]);
system("paccache -rk2");
//System backup
get_date(date); //Get the date of today and pass it to the array
backup_path_ptr = make_backup_dir(DEV_PATH, date); //Create backup dir and get its path
backup_sys(backup_path_ptr); //Backup system to the backup_path_ptr dir
return 0;
}
/*
*This function will delete the given argument dir.
*/
void delete_dir(char *dir_path) {
char command_buffer[100];
//Copy command to buffer (rm -rf dir_path) to delete dir.
strcpy(command_buffer, "rm -rf ");
strcat(command_buffer, dir_path);
system(command_buffer); //Execute command
}
/*
*This function will get the date of today, and it'll insert it to the passed date array.
*/
void get_date(int *date) {
long int sec_since_epoch;
struct tm current_time, *time_ptr;
sec_since_epoch = time(0);
time_ptr = ¤t_time; //Set time pointer to the current_time struct
localtime_r(&sec_since_epoch, time_ptr);
//Pass today's date to the array
*date = time_ptr->tm_mday;
*(date+1) = time_ptr->tm_mon + 1; //+1 because months range from 0 - 11
*(date+2) = time_ptr->tm_year - 100; //-100 because tm_year is the passed years since 1900
}
/*
*A function that gets pointer to int array that contains the
*date of today and it converts it to string name so itll create
*a backup dir in the passed path with converted string.
*Then it will return the full path of the created dir to
*make backup in it.
*/
char *make_backup_dir(const char *device_path, int *date_array) {
int i;
char dir_name[9], command_buffer[100];
static char full_path[50]; //The returned full path
strcpy(command_buffer, "mkdir "); //Insert command to the command_buffer
strcpy(full_path, device_path);
//Convert the date_array to a strin so will use it to name the dir
sprintf(dir_name, "%02d", *date_array);
sprintf((dir_name+3), "%02d", *(date_array+1));
sprintf(dir_name, "%02d", *date_array);
sprintf(dir_name+6, "%d", *(date_array+2));
dir_name[2] = dir_name[5] = '-';
strcat(full_path, dir_name); //Complete the full dir path
strcat(command_buffer, full_path); //Complete the command
system(command_buffer); //Execute the command
return full_path;
}
/*
*This function will make the full system backup using rsync to the passed dir.
*/
void backup_sys(char *backup_path) {
const char *backup_command = "rsync -aAXHv --exclude={\"/dev/*\",\"/proc/*\",\"/sys/*\",\"/tmp/*\",\"/run/*\",\"/mnt/*\",\"/media/*\",\"/lost+found\"} / ";
char command_buffer[200];
//Prepare command
strcpy(command_buffer, backup_command);
strcat(command_buffer, backup_path);
system(command_buffer);
}
As @thatotherguy said, the solution is add setuid(geteuid());
to the code, plus changing the ownership to root and giving the users s mode (setuid).
Update: As it was noted it is not recommended to use the setuid mode because it causes many security holes!
This is main.c:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
printf("My real UID is %d\n", getuid());
printf("My effective UID is %d\n", geteuid());
}
Then:
gcc main.c -o main
sudo chown root:root main
sudo chmod 6711 main
./main
Output:
My real UID is 1234
My effective UID is 0
In other words, I'm still "really" myself (UID 1234) but I'm effectively root (UID 0).
Does this not work for you?
Update: Okay, it does.
Next step is to get rid of the system
call because your root privileges won't carry over to the program you execute via system. (By the way, to understand the problem with this, consider that the shell is going to find paccache
by looking at your PATH, which means that anyone who is able to arrange for a program called paccache
to appear in your PATH could trick you into running it as root.)
The way to launch a process in Linux is to call fork
, which will split the process into a parent and a child, then call execl
in the child process. ( execl
will never return, so if you want to do stuff after child program ends, you need to do that in the parent.)
pid_t child_pid;
if (child_pid = fork()) {
int child_status;
// I'm the parent, wait for child to finish.
wait(&child_status);
} else {
// I'm the child; run the other program.
execl("/path/to/paccache", "paccache", "-rk2", NULL);
}
// Do whatever you want to do after paccache ends...
For a non-trivial program you'd probably want to check for errors from fork
, wait
, execl
, etc.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.