Normally this is done by making your binary suid-root.
One way of managing this so that attacks against your program are hard is to minimize the code that runs as root like so:
int privileged_server(int argc, char **argv);
int unprivileged_client(int argc, char **argv, int comlink);
int main(int argc, char **argv) {
int sockets[2];
pid_t child;
socketpair(AF_INET, SOCK_STREAM, 0); /* or is it AF_UNIX? */
child = fork();
if (child < 0) {
perror("fork");
exit(3);
} elseif (child > 0) {
close(sockets[0]);
dup2(sockets[1], 0);
close(sockets[1]);
dup2(0, 1);
dup2(0, 2); /* or not */
_exit(privileged_server(argc, argv));
} else {
close(sockets[1]);
int rtn;
setuid(getuid());
rtn = unprivileged_client(argc, argv, sockets[0]);
wait(child);
return rtn;
}
}
Now the unprivileged code talks to the privileged code via the fd comlink (which is a connected socket). The corresponding privileged code uses stdin/stdout as its end of the comlink.
The privileged code needs to verify the security of every operation it needs to do but as this code is small compared to the unprivileged code this should be reasonably easy.