简体   繁体   中英

Run program from standard user as a root

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 = &current_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM