command prompt program: how to allow user to enter unix commands? - c

I'm having trouble writing a C program that displays a command prompt (no problem here) which allows the user to enter unix commands & then displays the results. I've tried many things but I only started programming a year ago and haven't gone anywhere besides displaying the command prompt; I need help on how to accept unix commands + display their results.
My only constraint is that instead of the user providing an absolute path, I need my program to search the directories specified in the path environment variable and find the location of the command's executable. I don't understand how to do this either but searching online has told me this would be best using "getenv() to access the OS PATH variable and prefix the user-supplied command appropriately". Can anyone help me out here? Thanks for your assistance in advance.

Try popen(), which can be found here in the manpages.
Check this out:
#include <stdio.h>
#include <stdlib.h>
void write_netstat(FILE * stream)
{
FILE * outfile;
outfile = fopen("output.txt","w");
char line[128];
if(!ferror(stream))
{
while(fgets(line, sizeof(line), stream) != NULL)
{
fputs(line, outfile);
printf("%s", line);
}
fclose(outfile);
}
else
{
fprintf(stderr, "Output to stream failed.n");
exit(EXIT_FAILURE);
}
}
int main(void)
{
FILE * output;
output = popen("netstat", "r");
if(!output)
{
fprintf(stderr, "incorrect params or too many files.n");
return EXIT_FAILURE;
}
write_netstat(output);
if(pclose(output) != 0)
{
fprintf(stderr, "Could not run 'netstat' or other error.n");
}
return EXIT_SUCCESS;
}
This prints a netstat to a file. You can do this for all commands. It uses popen(). I wrote it because I needed a log of a netstat.

Related

Is there a simple way to find the owner of a Process in Unix using C?

I want to be able to check the owner of a process of which I got the ID from using C on a Unix system. It also needs to work on cygwin. Additionally it would be nice to get the date the process was created, too.
I've seen there are ways through looking up the generated files in /proc/<process-id>/. But unfortunately on cygwin you would need the right permissions to read those files.
If possible I am searching for a way without using those files or system commands. I had also found this threat:
How to programatically get uid from pid in osx using c++?
But it won't work due to missing definitions of KERN_PROC, KERN_PROC_PID and some more.
(Have not found the librarys for those in C)
So in short:
Does anyone know how I could get the informations on a specific process using c without needing system calls or reading the files in /proc/?
here under a simple implementation using ps command.
It's certainly not the most elegant but it should work for Unix and Cygwin:
#include <stdio.h>
#include <string.h>
int get_proc_uid(int pid, char *uid, int uid_size)
{
FILE *fp;
int pid_l, ret = -1;
char uid_l[16];
char cmd[64], line[128];
snprintf(cmd, sizeof(cmd), "ps | grep %d", pid);
fp = popen(cmd, "r");
if(fp == NULL)
return ret;
while(fgets(line, sizeof(line), fp) != NULL)
{
if(strstr(line, "grep") == NULL)//filter grep dummy result
{
sscanf(line, "%d %s", &pid_l, uid_l);
if(pid_l == pid)
{
strncpy(uid, uid_l, uid_size);
ret = 0;
break;
}
}
}
pclose(fp);
return ret;
}

Using stdin in C exclusively through a piped in file

I wrote a file parser for a project that parses a file provided on the command line.
However, I would like to allow the user to enter their input via stdin as well, but exclusively through redirection via the command line.
Using a Linux based command prompt, the following commands should yield the same results:
./check infile.txt (Entering filename via command line)
./check < infile.txt
cat infile.txt | ./check
The executable should accept a filename as the first and only command-line argument. If no filename is specified, it should read from standard input.
Edit: I realized how simple it really was, and posted an answer. I will leave this up for anyone else who might need it at some point.
This is dangerously close to "Please write my program for me". Or perhaps it even crossed that line. Still, it's a pretty simple program.
We assume that you have a parser which takes a single FILE* argument and parses that file. (If you wrote a parsing function which takes a const char* filename, then this is by way of explaining why that's a bad idea. Functions should only do one thing, and "open a file and then parse it" is two things. As soon as you write a function which does two unrelated things, you will immediately hit a situation where you really only wanted to do one of them (like just parse a stream without opening the file.)
So that leaves us with:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "myparser.h"
/* Assume that myparser.h includes
* int parseFile(FILE* input);
* which returns non-zero on failure.
*/
int main(int argc, char* argv[]) {
FILE* input = stdin; /* If nothing changes, this is what we parse */
if (argc > 1) {
if (argc > 2) {
/* Too many arguments */
fprintf(stderr, "Usage: %s [FILE]\n", argv[0]);
exit(1);
}
/* The convention is that using `-` as a filename is the same as
* specifying stdin. Just in case it matters, follow the convention.
*/
if (strcmp(argv[1], "-") != 0) {
/* It's not -. Try to open the named file. */
input = fopen(argv[1], "r");
if (input == NULL) {
fprintf(stderr, "Could not open '%s': %s\n", argv[1], strerror(errno));
exit(1);
}
}
}
return parse(input);
}
It would probably have been better to have packaged most of the above into a function which takes a filename and returns an open FILE*.
I guess my brain is fried because this was a very basic question and I realized it right after I posted it. I will leave it up for others who might need it.
ANSWER:
You can fgets from stdin, then to check for the end of the file you can still use feof for stdin by using the following:
while(!feof(stdin))

Exploiting c - linux setuid and system commands

I have the following code as an executable that I want to exploit for a course in order to spawn a shell with elevated privileges. I am a user of levelX and the executable has setgid of levelX+1. I am not allowed to alter any of the code.
As I do not have root privileges, setguid(0) fails. I was not able to change the return address of the function or main function. Could anyone point to the right direction?
int main (int argc, char** argv)
{
if (exec(argv[1]) != 0)
{
fprintf(stderr, "Cannot execute your command\n");
return -1;
}
return 0;
}
int exec(char *command)
{
FILE *f = NULL;
char entry[64];
char line[256];
f = fopen("log", "a");
if (f == NULL)
{
fprintf(stderr, "Can't open file\n");
return -1;
}
snprintf(entry, 64, "%d: %s\n", getuid(), command);
fprintf(f, entry, NULL);
fclose(f);
f = fopen("sudoers", "r");
if (f == NULL)
{
fprintf(stderr, "Can't open\n");
return -1;
}
while(fgets(line, 256, f) != NULL)
{
if (atoi(line) == getuid())
{
if (setuid(0) == 0) {
system(command);
} else {
fprintf(stderr, "check permissions\n");
}
fclose(f);
return 0;
}
}
fprintf(stderr, "Error\n");
fclose(f);
return -1;
}
From the code you posted, it appears you are supposed to write your own sudoers file to any directory you have write access to, then run this program in that directory, so it reads your file.
So, simply write your own UID to this fake sudoers file, and then give a command parameter such as bash to get a shell. There's no need to do any buffer overflow exploitation.
Presumably the real exploitable program has suid bit set in the file permissions, so it can perform the setuid(0) call. I guess the purpose of the exercise is to demonstrate how all input needs to be sanitized when you are dealing with suid programs, including things like relative paths (which effectively take current working directory as input) like any user-supplied paths and other input.
But, since the program only has setgid bit (as said in comment), you need find something you do with just the group id. That something could be that log file write. You could create a symbolic link with file name log, pointing to whatever file you want to append to, which that group has write permissions for. Also, that file needs to have format such, that the log line format does not make the file corrupted. Remember, you can put newlines etc into command line arguments!
After all it was a format string exploit on fprintf(f, entry, NULL); inside int exec(char *command) where you overwrite the return address with %n format.

Exclude file types expect txt files in C

Hello and Happy new Year ,
I have to accept juste txt files in my C programme ,
I don't have any idea to how to made it .. any ideas?
And I don't know if text file contain Header or something which characterize it..
PS: I'm using Ubuntu so file extension is not seen.
Thank you
In a Linux environment, I would personally go with libmagic, which is the core of the utility program file. The purpose of this library is to do exactly what you are trying to accomplish: identify the type of a file based on it content.
Example usage would look like this.
/* identify.c */
#define _POSIX_SOURCE /* required for fileno() */
#include <magic.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
const char *description;
magic_t cookie;
FILE *fp;
fp = fopen("example.txt", "r");
if(fp == NULL) {
fprintf(stderr, "error: cannot open file\n");
exit(EXIT_FAILURE);
}
cookie = magic_open(MAGIC_NONE);
if(cookie == NULL) {
fprintf(stderr, "error: cannot initialize library\n");
fclose(fp);
exit(EXIT_FAILURE);
}
if( magic_load(cookie, NULL) != 0 ) {
fprintf(stderr, "error: cannot load database : %s\n",
magic_error(cookie));
magic_close(cookie);
fclose(fp);
exit(EXIT_FAILURE);
}
description = magic_descriptor(cookie, fileno(fp));
printf("%s\n", description);
magic_close(cookie);
fclose(fp);
return EXIT_SUCCESS;
}
Name this source file identify.c, create a text file name example.txt with some content in the same directory, and compile with:
gcc -Wall -std=c99 -pedantic -lmagic -o identify identify.c
Then run it.
./identify
And you get something like this printed:
UTF-8 Unicode text
This library can be used in a few different ways, so you should probably have a look at the man page. For example, you can get a MIME type instead of a description like the one above.
The file package of which libmagic is a part is probably already installed on your machine. However, if you are using a distribution such as RHEL of CentOS that splits development headers into a separate package, make sure you have file-devel installed.

Confused about command prompt, Visual Studio exe's and text files?

The title doesn't really do this topic justice. It's actually quite simple, my problem that is. I have a program (code below) written in the C language. I want this program to create an exe file that can be ran through the command prompt console window and that will also take a text file as a parameter. So, long story short; I need it to say this on the command line in CMD:
C:\Users\Username\Desktop\wrapfile.exe content.txt
My only problem is getting the code right. I want to tell Visual Studio: "The file you should open is given in the command prompt window as a parameter, there is no set location..."
How do I do that?
Here is my working code (Although you will have to change a few things in the *fp definition.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp; // declaring variable
fp = fopen("c:\\users\\*Put you're PC username here*\\Desktop\\contents.txt", "rb"); // opens the file
if (fp != NULL) // checks the return value from fopen
{
int i;
do
{
i = fgetc(fp); // scans the file
printf("%c",i);
printf(" ");
}
while(i!=-1);
fclose(fp);
}
else
{
printf("Error.\n");
}
}
Thanks everyone!
As Ken said above, the arguments of the main method are the values that you pass in from the command line. Argc is 'argument count' and argv is 'argument values'. So to open the fist argument passed in from the command line, change
fp = fopen("c:\\users\\*Put you're PC username here*\\Desktop\\contents.txt", "rb"); // opens the file
to
fp = fopen(argv[1],"rb");
Just make sure to do error checking (ie argv[1] is not null) before you try to fopen the input. Also FYI, in your case argv[0] will be the name of your executable.

Resources