clinuxsqliteelevated-privileges

Raise privileges to open a sqlite3 root database on Linux - C programming


I'm creating a Linux software that will have two types of databases:

  1. Public: stores information that anyone on my_program_group has access (without root privileges);
  2. Private: only users with sudo access can open (common users on my_program_group can't). It also means that the database file is owned by root.

The first kind of the database is working fine.

The problem is: my program doesn't need to be run with sudo; so, if at some point a common user needs to open a private database, he will need to access root privileges (raise privileges). I don't want to ask restarting the execution with sudo, instead, just request for password.

#include <sqlite3.h>
#include <stdio.h>

// Private database path
#define PATH = "/tmp/test/database.db"

void private_db(sqlite3 **db);

int main() {
    sqlite3 *db;
    
    // When the user needs to open the private database, this function will be called:
    private_db(&db);
    
    // Continue...

    return 0;
}

void private_db(sqlite3 **db){
    int rc;

    // NEED TO RUN THIS AS ROOT:
    rc = sqlite3_open(PATH, db);
    if(rc  != SQLITE_OK) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg( &(**db) ));
        exit (1);
    } else {
        printf("Database successfully openend\n");
    }
}

(As expected) If I run the code above, sqlite won't be able to open the database because of the system permissions.


Solution

  • I revised a new code for you. Hoping it is helpful.

    Create a new file named db_helper.c and add the following code:

    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #define PATH "/tmp/test/database.db"
    
    int main() {
        int fd = open(PATH, O_RDWR);
        if (fd < 0) {
            perror("Can't open database");
            return 1;
        }
        printf("Database successfully opened\n");
        printf("Database file descriptor: %d\n", fd);
    
        // Pass the opened file descriptor to the parent process
        // Here, we use file descriptor number 3 for passing to the parent
        dup2(fd, 3);
        close(fd);
    
        return 0;
    }
    

    Compile the db_helper.c file, change the owner to root, and set the setuid bit:

    gcc -o db_helper db_helper.c
    sudo chown root:root db_helper
    sudo chmod 4750 db_helper
    

    Update your main program to use the helper program for opening the private

    database:
    #include <sqlite3.h>
    #include <stdio.h>
    #include <unistd.h>
    
    // Private database path
    #define PATH "/tmp/test/database.db"
    #define HELPER_PROGRAM "./db_helper"
    
    void private_db(sqlite3 **db);
    
    int main() {
        sqlite3 *db;
    
        // When the user needs to open the private database, this function will be called:
        private_db(&db);
    
        // Continue...
    
        return 0;
    }
    
    void private_db(sqlite3 **db){
        int rc;
        int fd;
    
        pid_t pid = fork();
        if (pid == 0) {
            // Child process
            execl(HELPER_PROGRAM, HELPER_PROGRAM, NULL);
            perror("execl");
            exit(1);
        } else if (pid > 0) {
            // Parent process
            wait(NULL);
        } else {
            perror("fork");
            exit(1);
        }
    
        // Read the file descriptor from the helper program (number 3)
        fd = 3;
    
        // Open the SQLite database using the received file descriptor
        rc = sqlite3_open_v2("db_alias", db, SQLITE_OPEN_READWRITE, NULL);
        if (rc != SQLITE_OK) {
            fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(*db));
            exit(1);
        } else {
            printf("Database successfully opened\n");
        }
    }
    

    And compile it:

    gcc -o main main.c -lsqlite3
    ./main