I'm creating a Linux software that will have two types of databases:
my_program_group
has access (without root privileges);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.
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