I'm having some problems with execve. I'm trying to make a shell that can function just like the bash shell, but I have problems with the forked child executing a command. Here is what I have for the child. cmd is a char * with the command that the user typed in. However, when I run this program, I get this error from perror:
execve error: No such file or directory.
I have tried the program with a simple ls, and it should make path="/bin/ls" and execute it (I have confirmed this is where my ls command is) but it still complains. What am I doing wrong? Thanks!
if(pid == 0)
{
// Parse the command
char * word = strtok(cmd, " ");
char path[128] = "/bin/";
strcat(path, word);
// Execute the process
char * newenvp[] = { NULL };
char * newargv[] = { path, NULL };
ret = execve(path, newargv, newenvp);
if(ret == -1)
perror("execve error");
return EXIT_SUCCESS;
}
The first thing I would do would be to insert:
printf ("[%s]\n", path);
before the call to execve. That should confirm that the executable is what you think it is.
That code of yours looks okay as long as the input you're feeding into it is correct and the executable actually is available. For example, the following complete program works fine on my Debian box:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
if (argc > 1) {
char * word = strtok (argv[1], " ");
char path[128] = "/bin/";
strcat (path, word);
char * newenvp[] = { NULL };
char * newargv[] = { path, NULL };
printf ("[%s]\n", path);
int ret = execve (path, newargv, newenvp);
if (ret == -1) {
perror("execve error");
}
}
return 0;
}
outputting, when I run ./testprog ls, something along the lines of:
[/bin/ls]
kidsshares.ods paxwords birthdays homeloantracking.gnumeric
shares2011.ods backup0.sh development lexar
accounts.ods backup1.sh photos testprog.c
testprog
If you don't want to manually travel through the fileystem to find the correct binary, there is execlp (with an additional p).
From the manpage:
The execlp(), execvp(), and execvpe() functions duplicate the actions of the shell in searching for an executable file if the specified
filename does not contain a slash (/) character. The file is sought in the colon-separated list of directory pathnames specified in the PATH environment variable. If this variable isn't defined, the path list defaults to the current directory followed by the list of directories returned by confstr(_CS_PATH). (This confstr(3) call typically returns the value "/bin:/usr/bin".) [...]
Related
I am a little bit stuck. I have a C program which includes the environmental variable $USER. The goal is to use the environmental variable to execute a different file using command injection.
I already tried different ways of declaring USER.
e.g.: Declaring USER as
env USER=">/dev/null ; cat /home/Steve/Public/file2.txt".
Unfortunately, that did not work.
C program:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
// Execute any shell command
void execute(char *cmd)
{
execl("/bin/bash", "bash", "-p", "-c", cmd, NULL);
}
void sanitise(char *password)
{
int i,j;
char tmp[15];
// remove non-alphabet characters from passwords
j=0;
for(i=0; i < 15; ++i)
if(password[i] >= 'a' && password[i] <= 'z') {
tmp[j]=password[i];
++j;
} else break;
tmp[j] = '\0';
strcpy(password, tmp);
}
int authenticate(char *str)
{
char stored_password[15]="";
char pass[15];
char path[128] = "/home/Steve/private/password";
int i;
FILE *fpp;
int auth=0;
fpp = fopen(path, "r");
if(fpp == NULL)
{
printf("Password file %s not found\n", path);
exit(1);
}
fgets(stored_password, 15, fpp);
sanitise(stored_password);
strcpy(pass, str);
sanitise(pass);
if(strcmp(stored_password,pass) == 0)
auth=1;
else {
auth=0;
}
fclose(fpp);
return auth;
}
int main(int argc, char* argv[], char *envp[])
{
char error[256] = "/home/Steve/Public/errormessage.sh $USER ";
char pass[15];
if(argc < 2)
{
printf("Usage: %s password\n", argv[0]);
return 0;
}
// copy only 15 characters from user input, to prevent stack smashing
strncpy(pass, argv[1], 15);
pass[14]='\0';
if(!authenticate(pass)) {
// Log all failed attempts
printf("Wrong password. This incident has been logged.\n");
strcat(error, pass);
execute(error); // Execute script to log events
return 0;
}
// Display 'secret-file2'
execute("cat /home/Steve/Public/file2.txt");
return 0;
}
The goal would be to make the program output the file from the variable USER and not the initial file path declared in the error char. Ideally, without changing the C program at all.
Can anyone please tell me what I am missing here?
If you wish to use your C program with a fresh seted ${USER} variable "env -i" is what you should use.
Example: env -i USER='injected code' name_of_c_program
If that's what the program is doing, it will execute the following command:
/home/Steve/Public/errormessage.sh $USER <provided-password>
Since you control the provided password (that is, you can pass what you want in argv[1] as long as it's max 14 characters), you can just execute another bash shell as well, and then use it to run any command you want. There really is no need to tamper with $USER.
$ ./program '; bash'
Wrong password. This incident has been logged.
$ <--- another bash shell has now started
$ cat /home/Steve/Public/file2.txt
...contents of file2.txt...
If you want to run it with a single command, this should work:
echo 'cat /home/Steve/Public/file2.txt' | ./program '; bash'
Use 'getenv' library function to get the value of environment variable(USER). And then run the command using 'system(path)'.
#include <stdlib.h>
...
char path[256] = "/home/Steve/Public/file1.sh ";
strcat( path, getenv("USER") );
//char path[256];
//sprintf(file,"%s%s","/home/Steve/Public/file1.sh ",getenv("USER"));
...
I have a C-program built on macOS High Sierra using gcc and a makefile. The first thing the program does is read a binary inputfile. The filename can be either specified from the terminal command line together with the shell command or the program will ask for it when it’s not specified.
My issue is that when the input file is not specified together with the shell command, the program returns an error, saying it cannot open the file.
Here’s what works and what doesn’t:
(program and input file are in the same directory)
open terminal
from the command line type:
./program_name –i input.dat
=> works fine
open terminal
from the commandline type:
./program_name
program prompts:
Inputfile:
I type: input.dat
=> error opening file
open Finder and go to directory with program and input file
doubleclick on program_name icon
program starts in terminal and prompts:
Inputfile:
I type: input.dat
=> error opening file
I run the very same source code on linux and windows where it works ok, so I think it must be an OS thing that I don't understand?
I can add that the program was untrusted because it doesn't come from the app store. CTRL-click on the icon solved that.
--EDIT - sorry for not adding the verifyable code.
To clarify: the argc/argv part works fine. it's the last section of the routine where it prompts for the file name where it goes wrong. Maybe it's indeed the path as Jabberwocky suggested. I'll check on that tonight and will follow-up here.
void GetFileName(nr_args, args, filename, json)
int nr_args;
char **args;
char *filename;
int* json;
{
int i = 1;
filename[0] = '\0';
/* the command 'interpreter' itself is stored in argv[0] */
while (i<nr_args) {
if (strcmp(args[i], "-e") == 0) {
/* we cannot set the json flag here, because */
/* flags have not been initialized yet */
*json = 1;
i++;
}
else {
if (strcmp(args[i], "-i") == 0) {
if (nr_args > i+1) {
/* inputfile was specified */
strncpy(filename, args[++i], MAX_ID_LENGTH);
i++;
}
}
else {
PrintError(41, NULL, args[i]);
i++;
}
}
}
if (filename[0] == '\0') {
printf("\n\nInputfile: ");
scanf("%19s", filename);
filename[MAX_ID_LENGTH] = '\0';
/* clear the input buffer, to prevent parsing an */
/* empty string as the first user command */
/* always do a getchar() independent of OS */
getchar();
printf("\n");
}
}
And this is the part where the file is opened (from main() )
/* Get filename */
GetFileName(argc, argv, inputfile, &json);
/* Open the datafile */
if ((datafile = fopen(inputfile, "rb")) == NULL) {
PrintError(40, NULL, inputfile);
ExitProgram();
return(OK);
}
EDIT2-- As per Andrew Henle's reply, this is the prototype.
void GetFileName(int, char**, char*, int*);
The function is called from the same file as it is defined in.
I run the very same source code on linux and windows where it works ok
That is meaningless.
This is an old K&R-style function definition:
void GetFileName(nr_args, args, filename, json)
int nr_args;
char **args;
char *filename;
int* json;
{
...
You can not call that function safely if the calling code uses a function prototype. A K&R-defined function expects all of its arguments to have underdone default argument promotion. A prototype for the function means the caller won't perform those promotions. The mismatch will result in undefined behavior.
Don't use such ancient functions. You can't use them with a prototype, and without a prototype you have no type safety in the function call.
Use a proper, C standard-compliant function definition:
void GetFileName( int nr_args, char **args, char *filename, int* json )
{
...
And then provide a proper prototype for all calls to the function.
I made the following routine that works for me.
So, as an example:
if the program is in location /usr/mac/my-name/programs/
and the input filename that was entered is input.dat
Then this routine will return: /usr/mac/my-name/programs/input.dat
Thanks for all your help.
#include <sys/param.h> /* realpath() */
#include <limits.h> /* PATH_MAX */
#include <mach-o/dyld.h> /* _NSGetExectablePath() */
char *GetFullPath(const char*);
#define MAX_FILENAME_LEN 100 /* or another value */
char *GetFullPath(const char *filename)
{
char path_buf[PATH_MAX + 1];
char resolved_name[PATH_MAX + 1];
char *real_path;
char *return_path;
uint32_t buf_size = sizeof(path_buf);
int index = 1;
/* this functions returns the full path of the current */
/* running application appended with var 'filename' at */
/* the end. In case of an error it returns NULL. */
if ((return_path = (char *) malloc(MAX_FILENAME_LEN)) == NULL) {
printf("GetFullPath(): error in Malloc()\n");
return(NULL);
}
/* get relative path */
if (_NSGetExecutablePath(path_buf, &buf_size) != 0) {
/* buffer too small */
printf("File Path too long.");
free(return_path);
return(NULL);
}
/* convert to absolute path */
if ( (real_path = realpath(path_buf, resolved_name)) == NULL) {
printf("Could not determine path.\n");
free(return_path);
return(NULL);
}
/* strip the application name from the end of the path */
index = strlen(real_path) - 1;
while (real_path[index] != '/') {
index--;
}
/* now check if there's enough room in return_path */
if (strlen(real_path) + strlen(filename) >= MAX_FILENAME_LEN) {
printf("File path too long.\n");
free(return_path);
return(NULL);
}
/* there's enough room, copy path and filename to return_path */
strncpy(return_path, real_path, index+1);
/* do not try to free() real_path */
return_path[index+1] = '\0';
strncat(return_path, filename, strlen(filename));
return(return_path); /* caller must free() return_path */
}
I need to create a program that basically acts similarly to the list utility on Linux. I've been trying to get this to work and I'm pretty close but now I've gotten stuck. Essentially it will print whatever files and sub-directories that are contained withing a directory(i.e. if i run ./project3, it lists whatevers in that directory). However, once I try to get the recursive call working it spits out something like:
sh: 1: /home/RageKage/Documents/Project3/dir1: Permission denied
That's where I'm stuck, I'm not exactly sure what to do from here. I'm getting the path of the directory to explore using realpath and that works fine, but the recursive call just isn't working and I'm not exactly sure what I'm doing wrong. Any help would be appreciated as I'm relatively new to this.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <limits.h>
int main (int argc, char *argv[])
{
DIR *dir;
struct dirent *sd;
const char *direct;
char buf[PATH_MAX + 1];
if (argc < 2)
{
direct = ".";
}else{
direct = argv[1];
//printf("Hey this is argv[1]: %s\n", argv[1]);
}
dir = opendir(direct);
if (dir == NULL)
{
printf("ERROR! NO DIRECTORY TO OPEN!\n");
exit(1);
}
while( (sd=readdir(dir)) != NULL )
{
if (!strcmp(sd->d_name, ".") || !strcmp(sd->d_name, ".."))
{
}else{
printf("\n>> %s\n", sd->d_name);
}
if (!strcmp(sd->d_name, "..") || !strcmp(sd->d_name, "."))
{
}else if (sd->d_type == 4){
printf("Attempting to Run!\n");
realpath(sd->d_name, buf);
printf("[%s]\n", buf);
system(("./project3 %s", buf));
printf("\n");
}
}
closedir(dir);
return 0;
}
system(("./project3 %s", buf));
Are you recursively calling the program itself again? That sounds a bit inefficient, and hard to do since you'd need to know where the executable file is. In general it could be just about anywhere (starting with /bin, /usr/bin etc.), and all you are likely to get in argv[0] is the filename part, not the whole path.
Also, as said in the comments, func((this, that)) is the same as func(that), not func(this, that), since the parenthesis make the comma act as the comma operator, not as an argument separator. And system() only takes one argument anyway, so you'd need to use sprintf() to build the command line. (Or perhaps use the exec() functions to actually give separate arguments without invoking a shell, but then you need to do the fork(), too.)
I'd suggest scrapping that idea, and putting the directory tree walking into a function of it's own, and calling that recursively:
void walkpath(void)
{
DIR *dir = opendir(".");
struct dirent *sd;
while((sd = readdir(dir)) != NULL) {
/* ... */
if (sd->d_type == DT_DIR) {
chdir(sd->d_name);
walkpath();
chdir("..");
}
}
}
int main(...)
{
/* ... */
chdir(directory);
walkpath();
}
I used chdir here to change the process's working directory along with the walk. If you need to track the full directory name, then you'll need to add that.
Also, now you have the test for . and .. twice. Use continue to end that iteration of the loop so you don't need to test the same thing again.
if (strcmp(sd->d_name, ".") == 0 || strcmp(sd->d_name, "..") == 0) {
continue;
}
I have written a small code which takes input from the user and passes it to the system ("command>/tmp/j"), here the file j is being created but there is no information inside it related to the input present in the command.
For eg: If I have given ps -f as input to the string command, the system() should execute it and store it inside file /tmp/j, but here the file j is being created but there is no output data inside it.
I have seen many questions, but all those are using popen() and the input is predefined in them.
#include<stdio.h>
#include<sys/syscall.h>
main()
{
enum msgtype {PROCESS_LIST_REQUEST=1, PROCESS_LIST_RESPONSE, DIRECTORY_LIST_REQUEST, DIRECTORY_LIST_RESPONSE, ERROR_REQUEST};
struct head
{
int version;
int msg_length;
int header_length;
enum msgtype msg_type;
char data;
char *reqtype;
};
struct head *buf;
buf = malloc((sizeof(struct head)));
buf->reqtype=malloc(40);
char req[10];
char *command;
command = malloc((sizeof(char) * 10));
fgets(req, sizeof(req),stdin);
buf->reqtype = req;
printf("%s" , buf->reqtype); //just to make sure correct thing is present
command = buf->reqtype;
printf("%s",command);//just to make sure correct thing is present
system ("command>/tmp/j");
{
FILE *fp;
char c;
fp = fopen("/tmp/j", "r");
if (fp == NULL)
printf("File doesn't exist\n");
else {
do {
c = getc(fp);
putchar(c);
} while (c != EOF);
}
fclose(fp);
}
}
This line
system ("command>/tmp/j");
Tries to run an executable literally called command, and redirects its output to /tmp/j. The redirection happens, thus creating the file /tmp/j, but then command (whatever it may be) produces no output.
Also, this
command = malloc((sizeof(char) * 10));
followed by this
command = buf->reqtype;
causes the memory from the malloc() call to leak.
As somebody else says
system ("command>/tmp/j");
tries to run a program called 'command'. YOu need to do
char buff[256];
snprintf(buff, sizeof(buff), "%s>/tmp/j", command);
system(buff);
Is there a way to open a file with the open() without knowing its full name?
The linux shell provides an easy way to do that (in some sense), by accepting regular expressions as input.
For example, if you have a folder containing the files:
a.out file1 file2 file3 file4 file.txt test
and you want to list only the files with the prefix file you can do so by:
$ ls file*
file1 file2 file3 file4 file.txt
Or:
$ ls file[1-9]
file1 file2 file3 file4
To list only numbered files and so on...
I need to open the same file whenever my program launches.
The problem is, the file it needs to open is of the form: X*Y, meaning it starts with an X and ends with Y, but it could be anything in between.
For example, it could be X-Toshiba_12.45y9-Y, or it might be X-Dell-5.44s-Y.
I want to be able to open this file without having to consider the model.
The file may reside with some other files in that folder, but the X prefix and Y postfix are unique.
I could iterate the files in that folder and try to find my file by matching strings, but I'd rather avoid it.
Is there a way to provide open() with a regular expression somehow?
These are not regular expressions! You are talking about glob patterns.
You can use the POSIX.1-2001 glob() function to expand a glob pattern (like *.* or foo-*.?a* or *.[a-z]* and so on) to an array of filenames/pathnames that match the given pattern (starting at the current working directory, unless the pattern specifies an absolute path). This is basically what most shells use when they expand file name patterns.
If you were hell-bent on using regular expressions to specify file names (say, you need find-type behaviour, but with regular expressions), use SUSv4 nftw() function to traverse a directory tree -- it even works with the corner cases, like fewer descriptors than tree depth, or files modified, renamed, or moved while tree traversal --, and POSIX regex functions to filter on the file names. Note: regcomp() and regexec() etc. are built-in to POSIX.1-2001 -supporting C libraries, and that includes just about all current C library implementations for Linux. No external libraries are needed at all.
It makes me very sad to see example code using opendir()/readdir() to traverse a directory tree, when nftw() is available and much smarter and more robust. Just define _XOPEN_SOURCE 700 and _POSIX_C_SOURCE 200809L to get all these nice features in Linux and many *BSD variants, too.
Check this example
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
int
startswith(const char *const haystack, const char *const needle)
{
size_t haystackLength;
size_t needleLength;
if ((haystack == NULL) || (needle == NULL))
return 0;
haystackLength = strlen(haystack);
needleLength = strlen(needle);
if (haystackLength < needleLength)
return 0;
return (memcmp(haystack, needle, needleLength) == 0);
}
int
endswith(const char *const haystack, const char *const needle)
{
size_t haystackLength;
size_t needleLength;
if ((haystack == NULL) || (needle == NULL))
return 0;
haystackLength = strlen(haystack);
needleLength = strlen(needle);
if (haystackLength < needleLength)
return 0;
return (memcmp(haystack + haystackLength - needleLength, needle, needleLength) == 0);
}
void
searchdir(const char *const directory, const char *const starts, const char *const ends)
{
DIR *dir;
struct dirent *entry;
dir = opendir(directory);
if (dir == NULL)
return;
while ((entry = readdir(dir)) != NULL)
{
struct stat statbuf;
char filepath[PATH_MAX];
size_t length;
const char *name;
name = entry->d_name;
if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
continue;
length = snprintf(filepath, sizeof(filepath), "%s/%s", directory, name);
if (length >= sizeof(filepath))
{
fprintf(stderr, "unexpected error\n");
closedir(dir);
return;
}
if (stat(filepath, &statbuf) == -1)
{
fprintf(stderr, "cannot stat `%s'\n", filepath);
continue;
}
/* if the entry is a directory, probably recures */
if (S_ISDIR(statbuf.st_mode) != 0)
saerchdir(filepath, starts, ends);
/* or just, continue? */
/* The file name does not match */
if ((startswith(name, starts) == 0) || (endswith(name, ends) == 0))
continue;
/* Do whatever you want with the file */
fprintf(stdout, "%s\n", filepath);
}
closedir(dir);
}
int
main(int argc, char **argv)
{
if (argc < 4)
{
fprintf(stderr, "usage: %s directory startpattern endpattern\n", argv[0]);
fprintf(stderr, "\tex. %s /home/${USER} X Y\n", argv[0]);
return -1;
}
searchdir(argv[1], argv[2], argv[3]);
return 0;
}
Do whatever you want with the file, can go from pushing it into a char * array, to passing a function pointer to the function and executing that function on the file path.