0

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.

Tux
  • 3
  • 3

1 Answers1

0

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
Richard-zrx
  • 201
  • 13
  • Perfect! I couldn't do without your help. On main, needs to include `stdlib.h` and `sys/wait.h`, and don't forget to change the "db_alias". For anyone having the same question, these links were helpful for me: https://www.gnu.org/software/libc/manual/html_node/Setuid-Program-Example.html https://stackoverflow.com/questions/2483755/how-to-programmatically-gain-root-privileges Thank you so much!! – Tux May 11 '23 at 00:52