Sunday, August 19, 2012

So you want to be root - calling sudo

Over the years, I have taken several different approaches to using sudo in my scripts.  When scripting expect-lite, the script either expects a response or it doesn't. sudo sometimes asks for a password, and other times it does not. Unfortunately, there is no built-in function to support sometimes.

But the need to use sudo remains. It is very useful when writing scripts which need to change file ownership, permissions, insert kernel modules or running tcpdump.

My latest technique of using sudo takes advantage of the sudo option '-S' which frees the script to not care if sudo requires a password.
# sudo password
$pass=secret

# run the ID command with sudo privileges
>echo "$pass" | sudo -S pwd
>sudo id
<uid=0


The sudo option '-S' means get the password from standard in (stdin). By using the echo command, it is easy to put the password on stdin and call sudo, as you can see in the above script. You will also note, that the second time I call sudo, I do not use the echo-technique, since I am expecting sudo to remember the previous authentication.

A note about sudo, the password which is passed to sudo, is in turn passed to the program (pwd in the above script). Not all programs take the password graciously, and in fact will give an error rather than execute as expected (tcpdump is one of these). Therefore, I find doing a seemingly non-related command like pwd is helpful in gaining authentication, and then executing the command I really want to run with sudo privileges.

There is a downside to the echo-technique. The user's password will be printed on the screen. However this can be somewhat mitigated by running the script as a test user (which has sudo privileges) rather than your user id. 

Go ahead, be root, it is easy with sudo in expect-lite.

Saturday, August 4, 2012

A tale of two scripts

One of the cool things about expect-lite is that it has a very simple interpreter, which ignores everything it doesn't understand, rather than giving a syntax error. You can paste just about any text into an expect-lite script, such as release notes, network diagrams, or sample output from commands, and have it ignored. This feature can be exploited.

In this post, I will embed a bash script inside an expect-lite script. I'll use the bash script to set up the environment, and then have the script call itself, this time using expect-lite as the interpreter. Since expect-lite ignores anything it doesn't know, it will ignore the embedded bash script.

Here's the script, bash_env.elt (with 755 permissions)
#!/usr/bin/env bash 
# Little bootstrap bash script to adjust env then run expect-lite

export EL_CONNECT_USER=user
export EL_CONNECT_PASS=secret
export EL_REMOTE_HOST=10.1.1.15
export EL_CONNECT_METHOD=telnet

# re-run the script as an expect-lite script
/usr/bin/env expect-lite c=$0 $*

# end the bash script, and return expect-lite pass/fail
exit $?

#start the expect-lite script
*EXP_INFO
@3
$myvar=hello world
$user=admin

>echo "$myvar"
<world
>

Run the script:
./bash_env.elt

The script starts out like any bash script, and then sets (and exports) some environment variables which control how expect-lite connects to a remote host. Then the bash starts expect-lite feeding it the script name ($0) and any parameters that might have been typed on the command line ($*). Finally, the bash script exits (exit $?) preventing bash from reading the rest of the script.

The final part of the script is expect-lite, which will be executed after expect-lite telnets to 10.1.1.15, and logs in with credentials user and secret.

Of course, you don't want to hard code these parameters for every script. After all, you may use telnet as your connect method today, and change to ssh later.

Embedding other scripts inside expect-lite scripts might just solve your challenging problem.