Originally Posted by
flp1969
Environment variables are kept by the parent process (not the 'shell') and inherited by child processes.
Well, when calling a program from shell (bash, csh, zsh or whatever shell is in use), the shell fork()s and exec()s the called program and becomes the parent process. That is why environment variables from the shell are accessible in the called program. But I don't really see, how this is related to any of my problems. I was just talking about a hypothetical shell-script which might pipe the value of a variable to veracrypt. But let's not go deeper into this. I think the approach via C will be fine. Thanks for the explanation though.
Not "destroys" but deallocate, probably.
This is what I mean. So I aim to "destroy" the data properly. It is just because I don't feel so comfortable with my password remaining somewhere in RAM till it gets overwritten by chance. This is all I care about.
As for getpass(). You can use fgets() ou getline(), using tcgetattr() and tcsetattr() (termios) to turn ECHO off.
Thanks for this. I will implement this.
Here's how you get the return status from a child process. Since we have just one forked process, wait() will be sufficient.
Also thanks for that hint. I created the function success(char*,char*), which basically waits for the child. So here is the problem that I came across: I can wait for the child created at first without any problems (line 102). But I want to check whether all volumes where mounted properly (and if not, print an error message, which one wasn't). For some reason, which I don't understand, waiting for the children of the child (created in line 59), waiting (line 69) doesn't work. See the following code:
Code:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <sys/wait.h>
#define READ_END 0
#define WRITE_END 1
void success(char *container, char *mountpoint)
{
int status;
printf("\nDEBUG: Waiting for mounting of \t%s\tat %s\n", container, mountpoint);
wait(&status);
if(status == 0) printf("Successfully mounted \t%s\tat %s\n", container, mountpoint);
else {
printf("Error mounting \t%s\tat %s\t<< return value:%d\n", container, mountpoint, status);
exit(2);
}
}
int main(int argc, char* argv[])
{
if(argc > 1 && argc%2==1)
{
int inst = (argc-1)/2;
int fd[inst][2];
pid_t pid;
char scmd[] = "veracrypt";
for(int i = 0; i<inst;i++){
pipe(fd[i]);
}
pid = fork();
if(pid==0)
{
int j=0;
dup2(fd[0][READ_END], STDIN_FILENO);
close(fd[0][WRITE_END]);
close(fd[0][READ_END]);
bool b = true;
for(int i=0;i<inst-1 && b;i++){
pid = fork();
if(pid==0){
j = i+1;
dup2(fd[j][READ_END], STDIN_FILENO);
close(fd[j][WRITE_END]);
close(fd[j][READ_END]);
}
else{
j = i;
b = false;
//success(argv[(j+1)*2+1],argv[(j+1)*2+2]);
}
}
printf("\nDEBUG: Attempting to mount \t%s\tat %s\n", argv[(j)*2+1],argv[(j)*2+2]);
//freopen("/dev/null", "w", stdout);
execlp(scmd, scmd, "-t","--protect-hidden=no","--keyfiles=","--pim=123",argv[j*2+1],argv[j*2+2],(char*) NULL);
fprintf(stderr, "Failed to execute '%s'\n", scmd);
exit(1);
}
else
{
char *buffer = getpass("Veracrypt Password:");
for(int i=0;i<inst;i++)
{
close(fd[i][READ_END]);
write(fd[i][WRITE_END], buffer, (strlen(buffer)+1));
}
for(int i=0;i<inst;i++){close(fd[i][WRITE_END]);}
srand(time(0));
for(int i = 0; i<strlen(buffer); i++) buffer[i] = rand();
free(buffer);
success(argv[1],argv[2]);
}
}
return(0);
}
If compiled like above, the program runs as expected, when entering a wrong password:
Code:
% ./myprogram /path/to/container1 /path/to/mountpoint1 /path/to/container2 /path/to/mountpoint2
Veracrypt Password:
DEBUG: Attempting to mount /path/to/container1 at /path/to/mountpoint1
DEBUG: Attempting to mount /path/to/container2 at /path/to/mountpoint2
DEBUG: Waiting for mounting of /path/to/container1 at /path/to/mountpoint1
Enter password for /path/to/container1:
Operation failed due to one or more of the following:
- Incorrect password.
- Incorrect Volume PIM number.
- Incorrect PRF (hash).
- Not a valid volume.
Enter password for /path/to/container1: Enter password for /path/to/container2:
Error mounting /path/to/container1 at /path/to/mountpoint1 << return value:256
% Operation failed due to one or more of the following:
- Incorrect password.
- Incorrect Volume PIM number.
- Incorrect PRF (hash).
- Not a valid volume.
Enter password for /path/to/container2:
I know, the output is very ugly (also because it is mixed with the veracrypt output), but it is just for debugging purposes.
The output shows that both children are started. After veracrypt fails to mount container1, veracrypt's verbose error message is printed to the screen and then my error message is printed, the parent exits and I am back in my shell (notice the "%" in the output). The second veracrypt process still runs in background and generates its output.
If I remove the comment in line 69 and call the function success(char*,char*) at that point, things stop working:
Code:
% ./myprogram /path/to/container1 /path/to/mountpoint1 /path/to/container2 /path/to/mountpoint2
Veracrypt Password:
DEBUG: Attempting to mount /path/to/container1 at /path/to/mountpoint1
DEBUG: Attempting to mount /path/to/container2 at /path/to/mountpoint2
DEBUG: Waiting for mounting of /path/to/container1 at /path/to/mountpoint1
This is the whole output. I consider this behaviour rather weird, since execlp is called immediately after printing the "Attempting to mount" message, but veracrypt doesn't generate any output. It appears in the process list though.
(Calling just "./myprogram /path/to/container1 /path/to/mountpoint1" works fine in both cases, since line 69 is not executed in that case)
I hope this explanation of my problem will be sufficient for understanding, what's going on. If I was ambiguous or did not elaborate enough on anything, just ask.
Maybe it is really just a very stupid thing, that I've overlooked, but I appreciate any help with this. It is the first time I work with fork()s and there's still much to learn.
Also nesting several fork()s and this array of several pipes seems kind of unprofessional to me. If there is a better better solution to call several instances of a program (veracrypt) and piping data to them, I would be glad to hear about that.
Thanks to everyone, who is digging through this code!!!
oneone.