Showing posts with label help. Show all posts
Showing posts with label help. Show all posts

Tuesday, July 1, 2008

Using Strings To Safely Get Program Usage Information On Linux And Unix

Hey There,

We've posted quite a bit about the "strings" command in various past-posts running the gamut from using strings to extract RPM header information to using the basic strings construct in C to make running shells on network sockets possible. Today we're going to take a look at the "strings" command in an entirely new light.

Imagine that you were tasked with running a particular command named, for the sake of argument, BLARG. Unfortunately, in our manufactured situation, BLARG has no man page, and searches for it in Google, and other search engines turn up no useful information. Also your boss just said that you needed to run it, and left it at that, with no further instruction (he also can't be reached. What's wrong with this guy? ;) BLARG is also a compiled binary.

Your basic inclination might be to just run it without any arguments, as many commands (like "mkdir") will give you the usage information you need if you use this method, like so:

host # mkdir
usage: mkdir [-p] [-m mode] dirname ...


However, lots of other programs don't, so it's not the wisest choice. Remember that BLARG could potentially be a very harmful program. Running it without arguments may destroy things you can't afford to lose.

Other options you have, would include (but not be limited to), the following, coupled with their undesirable possible outcomes:

1. You could give the command a bogus switch line, like "BLARG -xKECVDSLdlske" : Assuming that that command line is indeed bogus, lots of programs silently ignore bogus switches and run their default instructions anyway.

2. You could cat the command : This will probably just turn your terminal output into Chinese. Even if you redirect standard error to /dev/null, odds are standard output is going to include a lot of funky characters that might cause more harm than good. You might also note that, a lot of the time, the usage message is printed to standard error and not standard output!

3. You could use eval to run the program, like "eval BLARG" : Unfortunately, even though it seems counterintuitive, eval just evaluates a condition or program's return status. Unfortunately, in order to get that, it has to run the command.

4. You could use commands like crash to get the information : This can be a great way to find out the information you need. By typing "crash -h BLARG" you should, theoretically, get a dump of all the help information you need. Unfortunately, not all distro's of Linux and Unix include it by default and not all distros' versions of crash operate the same. Some require you to be proficient in running a debugger against a dump file, afterward. Way too much hassle.

So far, we've gone through about 5 options, going from worse to better. There are probably a lot more than I'm thinking up here as I type (email them to me at eggi@comcast.net with comments if you'd like, as I'd love to do a follow-up to this post with more of that kind of information).

One way I've found that is virtually foolproof, and works in every distro I've tested, is to use the "strings" command to extract usage information. If you've ever used strings before, you know that distilling what it spits out when you run it against a command to a universally acceptable output of help information for any and/or all binaries is next to impossible. The Linux version of the crash command comes much closer to doing this, and doing it better. But, for the rest of us (even those without the privilege to run "crash"), we can still get the information we need using "strings", like so:

host # strings BLARG 2>/dev/null|egrep -i 'usage|help' <-- Note that strings generally requires the fully qualified name of the binary, like /bin/BLARG or ./BLARG
usage: %s [-abcdefGHIJKv] [file ...]

and you can even add the universal "%s" printf modifier to your egrep if you want to get all the lines that might contain useful help information, if you're not sure that the usage message is limited to a single line of output. This has the side effect of, sometimes, making the output a little messy, although (as some of you may have noted) the above usage display (while better than nothing) doesn't really help you. You'll probably be right 99% of the time if you guess the -v flag stands for verbose or version, but you never know. Using strings and grabbing all the lines with %s can provide more insight, if not a more distracting view of the binary's guts (of course, this output is from another command entirely ;)

host # strings BLARG 2>/dev/null|egrep -i 'usage|help|%s'
%s: %s
%s: directory causes a cycle
%s %*u %-*s %-*s
ls: %s: %s
%s/%s
usage: %s [-abcdefGHIJKv] [file ...]
%ld%s-blocks
%s: unknown blocksize
%s: minimum blocksize is 512
%s:
%s: %m
netgroup: Cycle in group `%s'
%s.%s
(%s,%s,%s)
option requires an argument -- %s
unknown option -- %s
stack overflow in function %s
%.3s %.3s%3d %2.2d:%2.2d:%2.2d %s
%H:%M:%S
%a %b %e %H:%M:%S %Z %Y
%I:%M:%S %p
%s/%s.%d
YP server for domain %s not responding, still trying
<; errno = %s
%s: %s - %s
%s/bt.XXXXXX
%s/_hash.XXXXXX


Worst case, you can just run something like:

host # strings BLARG >OUTPUT 2>&1

and safely cruise the lines of text in the OUTPUT fiel to manually find what you need. You may have to ;)

In any event, you've got a great tool at your disposal to find out what you need to know the hard way. And, sometimes, that's the only way to be absolutely sure :)

Cheers,

, Mike

Tuesday, April 8, 2008

Usage And Compile Help For Linux/Unix Network Port Shell Program

Hey there,

Today's post is a follow up to yesterday's post on running a shell on a network socket. There are a few notes we'd like to add regarding compilation and usage, once you've got the program up and running on your Linux or Unix server.

First, the compile time note. Additional testing on other flavors of Linux showed that neither:

#include <sys/byteorder.h>

nor

#include <sys/endian.h>

worked on all systems :( We did find that this Linux "include" seems to work as a handy substitute for either:

#include <linux/byteorder/generic.h>

Of course, if none of these options work for you, we put comments in the code that name the functions and/or declarations that we're trying to grab from each of the includes. So, if you still find yourself in a pickle after trying all 3 of these include statements, you can probably find the correct include (.h header file) by typing the following at your command prompt:

host # find /usr/include |xargs egrep 'htons|htonl' /dev/null

It may be a bit tricky trying to find the correct include file, but it will probably have a name very similar to the 3 noted above.

Now, on to the fun stuff: Usage :)

To get this out of the way, if you've compiled and used the program to run a Linux or Unix shell on a network socket, you've probably noticed that the input and output don't behave exactly as you would expect in a regular shell.

Note that this line in the code:

execl("/bin/sh","sh",(char *)0);

was originally attempted in the following two manners (to try and force an interactive shell):

execl("/bin/sh","sh","-i",NULL); <--- Socket would connect, but then it would disconnect you immediately
execl("/bin/sh","sh","-i",(char *)0); <--- Socket would connect, and it wouldn't look ugly, but it wouldn't do anything else either (and we made sure it wasn't just an issue with echo by touching some files and verifying that they never got "touched" ;)

When all was said and done, this was the quickest, and dirtiest, way we could get the shell to answer on the network socket and be truly interactive. However, as mentioned above, it doesn't quite behave the way you might assume. Even shell built-in's don't work correctly for the most part, like in this mini-run-through:

host # ls
. .. netsock netsock.c
host # ./netsock
host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
ls
: command not found
pwd
: command not found
id
: command not found
echo
: command not found


Yet, strangely enough, "echo," with arguments, works (???):

echo hi
hi


although "eval" doesn't work, straight up:

eval ls
: command not found


Now, we can start to have some fun :) Using the backtick operators to execute an "eval" statement and echoing that, we can actually do something, and get confirmation back on our terminal!:

echo `eval ls`
netsock netsock.c
<--- This will always pump the output out on one line, so if you have a lot of files in your directory, you'll get back a long long line.
echo `eval pwd`
/export/user/bin
echo `eval id`
uid=0(root) gid=0(root) groups=0(root)
<--- This will be your PID if you started the program, which may be good enough if you just need to get in and do something that doesn't require privilege. Note that this program runs the shell on the socket under the UID and GID of the user that invokes it (or their effective UID and GID at that time)
echo `eval touch TOUCHY`
<--- We'll touch something, just to see if it works. Of course, we get no terminal response to indicate success, but that's normal since we don't have a prompt to return to.

Now, if we disconnect from the Telnet connection and do an ls, we should have an extra file waiting for us:

^]
telnet> q
Connection closed.
host # ls
. .. netsock netsock.c TOUCHY


Good deal :) Now we'll write a simple script and see if we can execute it from the shell attached to the network port. If this works, it'll be much easier to stage work for the future:

host # vi test.sh
host # chmod 700 test.sh
host # cat test.sh
mkdir a
cd a
touch file
echo "ALL SET"
host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
echo `eval ./test.sh`
ALL SET


And we get the output we expected! Just need to disconnect from Telnet again and check to make sure it actually did everything it was supposed to, and not just run the echo statement.

^]
telnet> q
Connection closed.
host # ls
. .. netsock netsock.c TOUCHY
a
host # ls a
. .. file


Success! Here's hoping this "how to" and compilation-assistance post helps you get more out of this program. If you haven't got the code already, please check out our post on running a shell on a network socket and have a blast!

Just, please, be considerate of others :)

Best wishes,

, Mike