ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I need to execute a shell program in C but I also need to see what was the output of that program so how is it possible in C with sytem() or other function call?
You can create a pipe, fork the program, then use dup2 in the child process to duplicate the write end to take the place of standard output (1), then call one of the exec* functions. The parent process can read from the read end of the pipe to get the output of the program. Here is an example, this calls a no argument command and converts the output to upper case.
Code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#define BUF_SIZE 256
int main(int argc, char *argv[]) {
char * cmd;
char buf[BUF_SIZE+1];
int pipe_fd[2];
int pid;
FILE * in;
int i;
if (argc < 2) {
printf("Usage: %s command\n", argv[0]);
return 0;
}
cmd = argv[1];
/* create a pipe */
if (pipe(pipe_fd) != 0) {
perror("pipe failed");
return -1;
}
pid = fork();
if (pid == 0) {
/* child process */
close(pipe_fd[0]); /* no need to keep the read end
around */
/* replace standard output */
if (dup2(pipe_fd[1], 1) < 0) {
perror("dup2 failed");
close(pipe_fd[1]);
return -1;
}
close(pipe_fd[1]); /* no need for the original
write end */
if (execlp(cmd, cmd, NULL) == -1) {
perror("execl failed");
}
close(1);
return -1; /* only called if execl failed*/
}
/* server process */
close(pipe_fd[1]); /* so the read end closes when
the child process exits */
in = fdopen(pipe_fd[0], "r");
if (in == NULL) {
fprintf(stderr, "Failed to open FILE from file descriptor\n");
return -1;
}
while (fgets(buf, BUF_SIZE, in) != NULL) {
for (i = 0; i < strlen(buf); i++) {
buf[i] = toupper(buf[i]);
}
printf("%s", buf);
}
return 0;
}
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789
Rep:
Although it shows a good example about how to use popen, beware that this last code is also a good example of what must not be done in term of security.
The issue is it doesn't check against malicious parameters. Should you expose this script to a hostile user, it can wipe out your files, install backdoors, etc ...
Although it shows a good example about how to use popen, beware that this last code is also a good example of what must not be done in term of security.
The issue is it doesn't check against malicious parameters. Should you expose this script to a hostile user, it can wipe out your files, install backdoors, etc ...
Ah, yes. That is true. This line is really wrong:
Code:
printf(line);
It should have been (of course):
Code:
printf("%s", line);
Thanks for pointing at that.
Fixed in the my previous post.
You spotted that bug but there is another one which is larger and easier to abuse ...
Look closer !
Hmm, I'm not so sure about that.
Though arguably not in the most beautiful way, the program does check correctly if the argument will overflow the buffer.
Are you still sure? If so, please tell me where it is. Thx
Well, this is kind of silly, since it is just an example to help the OP, but you didn't include the + 1 in your bounds check for the space. You also should only have MAXLINELEN for the argument to fgets, not MAXLINELEN + 1. Assuming the command runs as the user who called it, then I can't see any other issues with it.
Edit: That said, I didn't check the return value of the fdopen in my example. But we're not trying to demonstrate security and best practices here :P
Okay. The weakness is simpler than a stack overflow.
Pass this argument including the quotes to your program: "ls;cp /etc/hosts /tmp" and have a look at /tmp ...
If this program has normal permissions, then this isn't an issue. The user could do that anyway. Tricking the program to do it instead is just a more complicated way of doing it.
Okay. The weakness is simpler than a stack overflow.
Pass this argument including the quotes to your program: "ls;cp /etc/hosts /tmp" and have a look at /tmp ...
Yes, that does look ugly I must admit.
But, to my defense, there is no security danger in this (I think), since the user doing this "trick" with my program could as well do "cp /etc/hosts /tmp" without my program.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.