How to pass variables from a bash script to TCL? - bash

I have never used TCL before but am needing to use it in order to script commands in a tool we use. I have a bash script running that obtains some information from AD, which it will then pass to the TCL script to use. here is my bash script which runs without any issue.
echo "Enter username for LDAP Search"
read USERNAME
export USERNAME
echo "Enter password"
read -s PASSWORD
export PASSWORD
echo "What user do you want to add to Centrify?"
read CENTRIFY_USER
export CENTRIFY_USER
OBJECTSID=`ldapsearch -H ldap://my.domain.com:389 -D "$USERNAME#MY.REALM.COM" -w $PASSWORD -x -b "DC=my,DC=domain,DC=com" "(&(objectCategory=user)(sAMAccountName=$CENTRIFY_USER))" | grep objectSid | cut -d " " -f2`
SID=`/home/mydirectory/convert_objectSid_to_sid.sh $OBJECTSID`
export SID
echo "Adding user to Centrify..."
/home/mydirectory/add_users_to_centrify.sh
"add_users_to_centrify.sh" is the tcl script that is then called, but I get the error error during execution: can't read "USERNAME": no such variable in the tcl script.
Here are the contents of that:
#!/bin/sh
# \
exec adedit "$0" ${1+"$#"}
package require ade_lib
puts $env(USERNAME)
puts $env(PASSWORD)
puts $env(SID)
puts $env(CENTRIFY_USER)
bind my.domain.com $USERNAME {$PASSWORD}
Another issue, when the tcl script is called, all of the arguments I'm passing get printed, including the password. I had thought exporting would be the safest way to do this as it should only set the environment variables for this subshell and not print them. What's happening here?

The password is getting printed because you're explicitly printing the password (puts $env(PASSWORD)).
The error seems very clear: there is no variable in the tcl script named USERNAME. You could set one like this (and similarly for PASSWORD):
set USERNAME $env(USERNAME)
Or you could just use the environment variables directly:
bind my.domain.com $env(USERNAME) {$env(PASSWORD)}

Related

Securely reading password and passing it to multiple scripts - pass string to processes expecting input

I have a set of scripts that require a password to work, I coded them so that they read the password from user input instead of e.g. reading an argument or from a file so that the password is not persisted to the disk or shows on top.
I want to start all of them and avoid having to enter the same password multiple times.
The idea is to have a parent script that reads the password once then passes it somehow to all these scripts.
So first, in parent start_all.sh script:
read -p "pass > " pass
Now, I can't figure out how to use the value of $pass to start up all the child scripts that need that same password.
Assuming you don't want to pass the actual password on the command line to the subordinate scripts ...
One idea using a nameref:
$ head parent child
==> parent <==
#!/usr/bin/bash
stty -echo # disable echo of password value on command line
read -p "pass > " pass
stty echo # re-enable echo of command line typing
export pass # make available to subordinate scripts
child pass # pass *name* of variable containing password
==> child <==
#!/usr/bin/bash
declare -n newpass="$1" # define nameref
echo "child/pwd: ${newpass}"

Passing variable to Expect and Spawn

I'm writing a script that will scp a tar file from my local server to a remote host. Since the script generates the file through a pre-requisite process, the name is generated dynamically. My script needs to take the name of the file and pass it to scp for transfer.
#!/usr/bin/expect -f
spawn scp test.$(date +%y%m%d_%H%M).tar user#IP-ADDRESS:/destination/folder
set pass "password"
expect "password: "
send -- "$pass\r"
expect eof
I've tried setting the filename as a variable but keep seeing the same error:
can't read "(date +%y%m%d_%H%M)": no such variable
while executing "spawn scp test.$(date +%y%m%d_%H%M).tar user#IP-ADDRESS:/destination/folder"
$(date +%y%m%d_%H%M) is not a Tcl command. If you use expect, you have to learn Tcl. To get a formatted date in Tcl, use the clock command. Also, interpolation of the result from a command in Tcl is not done by $(....), but by [....]. You can find examples for this construct here.
Decided to go another route since the team was able to provision a new Artifactory repo for this binary and alike. However, to the advice provided here I was able to make a few discoveries which I used to fix my issues:
I also had a password with $ symbol and that also caused a world of issues.
#!/bin/bash
TEST=$(date +%y%m%d_%H%M)
/usr/bin/expect <<eof
set password {pas\$word}
spawn scp "$TEST" user#IP-ADDRESS:/destination/folder
expect "*password:"
send "$pasword\r"
expect eof

Read .properties file to set value in use and password field in Expect shell script

How to read values from Properties file for user and Password field in expect in shell?
Suppose if i have values.prop file having values like below,
user=abcd
pwd=xxxx
I want to set the above value in my test.sh as below
!/usr/bin/expect
set user "abcd"
set password "xxxx"
spawn ssh $user#$host
expect "$user#$hosts's password:"
send "$password\n"
If you can modify the format of the properties file then the easiest way would be to use the source functionality of tcl (expect script are practically tcl scripts).
!/usr/bin/expect
source values.prop
spawn ssh $user#$host
expect "$user#$hosts's password:"
send "$password\n"
With values.prop now looking like this:
set user "abcd"
set password "xxxx"
Here is a crude shell script which can automatically translate the properties file to a tcl file
#!/bin/sh
. "$1"
printf 'set user "%s"\n' "$user"
printf 'set password "%s"\n' "$password"
Use like this:
translate ./values.prop > values.prop.tcl
Then source values.prop.tcl in your expect script.

Pass a variable in a shell script

I'm new to Unix...I have a shell script that calls sqlplus. I have some variables that are defined within the code. However, I do not feel comfortable having the password displayed within the script. I would appreciate if someone could show me ways on how to hide my password.
One approach I know of is to omit the password and sqlplus will
prompt you for the password.
An approach that I will very much be interested in is a linux
command whose output can be passed into the password variable. That
way, I can replace easily replace "test" with some parameter.
Any other approach.
Thanks
#This is test.sh It executes sqlplus
#!/bin/sh
export user=TestUser
export password=test
# Other variables have been ommited
echo ----------------------------------------
echo Starting ...
echo ----------------------------------------
echo
sqlplus $user/$password
echo
echo ----------------------------------------
echo finish ...
echo ----------------------------------------
You can pipe the password to the sqlplus command:
echo ${password} | sqlplus ${user}
tl;dr: passwords on the command line are prone to exposure to hostile code and users. don't do it. you have better options.
the command line is accessible using $0 (the command itself) through ${!#} ($# is the number of arguments and ${!name} dereferences the value of $name, in this case $#).
you may simply provide the password as a positional argument (say, first, or $1), or use getopts(1), but the thing is passwords in the arguments array is a bad idea. Consider the case of ps auxww (displays full command lines of all processes, including those of other users).
prefer getting the password interactively (stdin) or from a configuration file. these solutions have different strengths and weaknesses, so choose according to the constraints of your situation. make sure the config file is not readable by unauthorized users if you go that way. it's not enough to make the file hard to find btw.
the interactive thing can be done with the shell builtin command read.
its description in the Shell Builtin Commands section in bash(1) includes
-s Silent mode. If input is coming from a terminal, characters are not echoed.
#!/usr/bin/env bash
INTERACTIVE=$([[ -t 0 ]] && echo yes)
if ! IFS= read -rs ${INTERACTIVE+-p 'Enter password: '} password; then
echo 'received ^D, quitting.'
exit 1
fi
echo password="'$password'"
read the bash manual for explanations of other constructs used in the snippet.
configuration files for shell scripts are extremely easy, just source ~/.mystuffrc in your script. the configuration file is a normal shell script, and if you limit yourself to setting variables there, it will be very simple.
for the description of source, again see Shell Builtin Commands.

Need to spawn a sourced shell script using expect

i'm using expect to automate some bash scripts. All goes right until i need to execute a sourced script; then i get this error:
couldn't execute "source setNAME.sh": no such file or directory
while executing
"spawn "source setNAME.sh""
(file "./setNAME.exp" line 2)
I use expect in a basic way (spawn/expect/send/interact); the problem is with spawn. Let me show a very easy example:
Script to read a name, echo the value and export to the environment as 'NAME':
/home/edu/scripts [] cat setNAME.sh
#!/bin/bash
echo "Your name?"
read name
export NAME=$name
echo "Provided NAME is $name"
If you execute with 'source' then the input value will be exported as environment variable. Just what i need:
/home/edu/scripts [] source setNAME.sh
Your name?
Dennis
Provided NAME is Dennis
/home/edu/scripts [] echo $NAME
Dennis
Let's to use expect to avoid interaction, setting 'edu' as the name:
/home/edu/scripts [] cat setNAME.exp
#!/usr/bin/expect
spawn setNAME.sh
expect "Your name?"
send edu\r
interact
/home/edu/scripts [] setNAME.exp
spawn setNAME.sh
Your name?
edu
Provided NAME is edu
/home/edu/scripts [] echo $NAME
Dennis
But the name, obviously, is still Dennis: 'edu' is shown at sh script output but not exported as NAME because expect script spawns the setNAME.sh script WITHOUT source (or dot before script).
The problem is that I CAN'T DO THIS because i get the error commented at the beginning.
Any ideas to solve/afford this need ?
In my case the script is much more complex and other solutions are also invalid, for example things like this:
source script.sh << EOF
<option1>
<option2>
...
EOF
That's the reason i'm trying to use expect...
Thanks a lot!
source is a shell builtin, not a system command, so you first need to spawn a shell then send the source command to it. That shell will then have the value in the NAME variable

Resources