Unix Cmds in a C program 
Author Message
 Unix Cmds in a C program

I am writing a program on the Solaris OS.  I need to make sure
that a particular directory is clear before I begin.  I want to
execute unix commands to this like cd dir and rm *.  What is the
best way to do this in a C program.  I know there is a system()
routine that you pass a cmd string to, but I have been told that
this is insecure.  Any ideas would be appreciated.  I have been
using for about 6 months now so hope that this is not a dumb question.

-joe



Mon, 01 Jan 2001 03:00:00 GMT  
 Unix Cmds in a C program

Quote:

> I am writing a program on the Solaris OS.  I need to make sure
> that a particular directory is clear before I begin.  I want to
> execute unix commands to this like cd dir and rm *.  What is the
> best way to do this in a C program.

The standalone UNIX commands are just interfaces to the
system calls (usually of the same name, a notable exception
being rm) -- you need more information on UNIX systems
programming. Stevens' Advanced Programming In The UNIX
Environment is the text you need.

Scott
--
Look at Softbase Systems' client/server tools, www.softbase.com
Check out the Essential 97 package for Windows 95 www.skwc.com/essent
All my other cool web pages are available from that site too!
My demo tape, artwork, poetry, The Windows 95 Book FAQ, and more.



Mon, 01 Jan 2001 03:00:00 GMT  
 Unix Cmds in a C program

Quote:

> I am writing a program on the Solaris OS.  I need to make sure
> that a particular directory is clear before I begin.  I want to
> execute unix commands to this like cd dir and rm *.  What is the
> best way to do this in a C program.  I know there is a system()
> routine that you pass a cmd string to, but I have been told that
> this is insecure.

I don't see anything insecure about a hard-coded shell command in a
binary executable program.  I would use "rm dir/*" vs. "cd dir; rm *"
because it is easier to catch errors (what happens if cd dir fails?).

char *szCommand="rm -f dir/*";

rc=system(szCommand);
if (rc<0) {
        fprintf(stderr,"Error executing %s", szCommand);
        }

Alternatively you could use opendir, readdir, closedir, unlink to delete
the files from the specified directory.  You'll need to use chdir to
change your program's current working directory (you can't use the
system command to do that since system creates a subshell).  There are
pros and cons to each method.



Mon, 01 Jan 2001 03:00:00 GMT  
 Unix Cmds in a C program


|> I don't see anything insecure about a hard-coded shell command
|> in a binary executable program.  

Look harder.  Consider something benign:

    #include <stdlib.h>
    int main(void) {
        system("ls");
        return 0;
    }

Now consider a particularly stupid system administrator whose
$PATH looks something like

    .:/usr/local/bin:/usr/bin:/usr/bin/X11:/usr/sbin

Assume /usr/local/bin is world (or at least group) writable.  Now
let's assume that root runs the above "benign" program.  There is
nothing that prevents a malicious user from putting a script
called "ls" into /usr/local/bin.  Perhaps the new version of ls
might look something along the lines of

    #!/bin/sh
    rm -rf /

Wonderfully functional.

Now certainly the malicious user doesn't have the permissions to
perform the above operation, but the superuser does, and that is
*exactly what will happen* when this particularly hapless system
administrator runs the harmless-looking C program.  This is one of
the oldest security holes in the book.

|> Alternatively you could use opendir, readdir, closedir, unlink
|> to delete the files from the specified directory.  You'll need
|> to use chdir to change your program's current working directory
|> (you can't use the system command to do that since system creates
|> a subshell).  There are pros and cons to each method.

system() should almost always be avoided in production code.  The
security issues, which can be mitigated by specifying a full path
to the executable (i.e., system("/bin/ls") is far, far safer) are
only one of the things to consider.  You also have to ask if you
really need the overhead of spawning a shell.  If you don't, the
fork()-and-exec() approach is considerably more streamlined.

The key argument for system() is generally one of the form "But
it's so easy to use!"  This is true, but being the easiest solution
isn't always a sign of being the *best* solution.  It's more work
from the programmer's perspective to use the POSIX dirent
facilities to remove a group of files than it is to simply "wipe
them out" with a single system() command.  But the former solution
is invariably more sound, and worth the extra effort (IMHO).

On the other hand, there are times when system() is useful,
especially in situations where you *want* a shell for the shell
functionality (i.e., wildcard and environment variable expansion.)
The key safety net is to fully specify the executable path to
avoid the problem described above.  It's unfortunate that we have
to deal with dangerous $PATH specifications, but not even software
developers can legislate common sense!

Regards,

--
Chris Engebretson - Raytheon STX Corporation | Ph#: (605)594-6829
USGS EROS Data Center, Sioux Falls, SD 57198 | Fax: (605)594-6940

Opinions are not those of  Raytheon Systems Company  or the USGS.



Mon, 01 Jan 2001 03:00:00 GMT  
 Unix Cmds in a C program

Quote:

> I am writing a program on the Solaris OS.  I need to make sure
> that a particular directory is clear before I begin.  I want to
> execute unix commands to this like cd dir and rm *.  What is the
> best way to do this in a C program.  I know there is a system()
> routine that you pass a cmd string to, but I have been told that
> this is insecure.

Hi Joe Condle,

The "system()" function is indeed the correct standard C way to
execute shell command. If you fear that there are Unix specifics
aspects to this you should best ask the Unix programming experts:

They will also be able to tell you about alternate Unix specific
(ie. non-portable) ways to execute shell commands.

Stephan
(initiator of the campaign against grumpiness in c.l.c)



Mon, 01 Jan 2001 03:00:00 GMT  
 Unix Cmds in a C program
Kind of off-topic, but I've found the easiest way is to pass the path to
the directory in as a funtion arg (nul-terminated string), have an auto
variable char array sized PATH_MAX, chdir() into the dir (check error),
have a length auto variable (length = srtren(arg1);), memcpy() that length
of characters from arg1 into the array, then call glob() to read the dir.

glob() does all of the opendir()/readdir()/closedir()/malloc() string
space for filenames in the background, where you don't personally have to
code it yourself. Then loop through the globvar.gl_pathv[] array in a do
loop, appending the filenames to the current working directory pathname in
the array (make sure the cwd path ends with "/"; if you are recursing,
GLOB_MARK in the flags will append "/" to any subdirectories that it
finds). stat() or lstat() each one to detect file type and access
permission (statvar.st_mode), and handle actual actions (unlink(), recurse
on subdirs, whatever it is you want to do) in a switch statement,
switching on

  switch (statvar.st_mode & S_IFMT) {
  case S_IFREG:  /* regular file */
  /* do regular file stuff */
  break;
  case S_IFDIR: /* subdirectory */
  ...

and so on. If you had GLOB_PERIOD in the flags (show files beginning with
"."), then check for "./" and "../" at the top of your loop, before the
stat() or lstat() call.

After you exit the loop, call globfree() to free() space that glob()
malloc()ed internally.

The only downside is that you don't get explicit notification of a
malloc() error if malloc() returns NULL on a call from within glob(), so
you don't know if you ran out of memory inside the glob() call, you just
get some vague error return from glob(), and errno may have changed by the
time glob() actually returns. But then you have the same problem with
opendir() when it malloc()s the stream buffer, and you still have to write
the equivalent glob() code yourself.

gnu make 3.76.1 (prep.ai.mit.edu:/pub/gnu/) has a new glob(), for people
using some version of glibc.


"Would that be 30 gallons of the Summer Paint or 30 gallons of
 the Winter Paint?"

--


"Would that be 30 gallons of the Summer Paint or 30 gallons of



Mon, 01 Jan 2001 03:00:00 GMT  
 Unix Cmds in a C program

Quote:

>I am writing a program on the Solaris OS.  I need to make sure
>that a particular directory is clear before I begin.  I want to
>execute unix commands to this like cd dir and rm *.  What is the
>best way to do this in a C program.  I know there is a system()
>routine that you pass a cmd string to, but I have been told that
>this is insecure.

system() is the only function the C language provides to execute system
commands. Your platform probably provides alternative methods but those
would need to be discussed in a platform related newsgroup such as
comp.unix.programmer. C provides the remove() standard library function
to delete a specified file but it has no support for directories or
directory searching (your platform probably does however).

--
-----------------------------------------


-----------------------------------------



Tue, 02 Jan 2001 03:00:00 GMT  
 Unix Cmds in a C program
I also had read somewhere that "system" was a possible security hole.
It was suggested to use something in the "exec*" group

I picked execle.

 rtn_status = execle ("/bin/ksh", "ksh", "-c", cmdstring, (char *) 0, environ) ;

Also, instead of doing a "rm dir/*" do a "/bin/rm dir/*"
The user might have aliased rm or have a different rm in their path.
This applies any command.

: >
: > I am writing a program on the Solaris OS.  I need to make sure
: > that a particular directory is clear before I begin.  I want to
: > execute unix commands to this like cd dir and rm *.  What is the
: > best way to do this in a C program.  I know there is a system()
: > routine that you pass a cmd string to, but I have been told that
: > this is insecure.

: I don't see anything insecure about a hard-coded shell command in a
: binary executable program.  I would use "rm dir/*" vs. "cd dir; rm *"
: because it is easier to catch errors (what happens if cd dir fails?).

: char *szCommand="rm -f dir/*";

: rc=system(szCommand);
: if (rc<0) {
:       fprintf(stderr,"Error executing %s", szCommand);
:       }

: Alternatively you could use opendir, readdir, closedir, unlink to delete
: the files from the specified directory.  You'll need to use chdir to
: change your program's current working directory (you can't use the
: system command to do that since system creates a subshell).  There are
: pros and cons to each method.

--
While DSC may claim ownership of all my ideas (on or off the job),
DSC does not claim any responsibility for them. Warranty expired when you
opened this article and I will not be responsible for its contents or use.



Mon, 15 Jan 2001 03:00:00 GMT  
 
 [ 9 post ] 

 Relevant Pages 

1. Newbie: separate big .cs file into small .cs files

2. Problem #30 on http://cs.nmu.edu/programming/c/problems.htm

3. SoftEng or CS Graduate Program Search

4. FS: Programming and CS Books --- CHEAP

5. 1995 UT IEEE CS National Programming Contest

6. Good CS Programs

7. IEEE CS National Programming Contest [Addendum3]

8. 1993 IEEE CS National Programming Contest Notice

9. Description of The 1991 IEEE CS National Programming Contest

10. 1993 IEEE CS National Programming Contest Addendum 2

11. 1993 IEEE CS National Programming Contest [Addendum]

12. Programming Language for Undergrad Intro CS Course?

 

 
Powered by phpBB® Forum Software