Script as login shell (passing args to login shell)

Hello all,

for security reasons my compagny imposes that my script be launch remotly via ssh under the users login shell.

So serverA launches the ssh command to serverB which has a local user with my script as a login shell.

Local script works like a charm on his own.

serverB$ grep user1 /etc/passwd
user1:x:921:921::/home/user1:/home/user1/insert_host_ip_named.bash

serverA$ ssh -t user1@serverB

Everything works fine until i bring up arguments

For testing purpose i've replaced the 3 first lines of my script with:

echo $#
echo $*
sleep 3
exit

and i get this:

 ssh user1@serverB -- "-i 275.30.44.55 -n WYWYOU"
2
-c -i 275.30.44.55 -n WYWYOU

Which is not good cause the script needs at least 4 args to run:

# Check number of arguments
case $# in
         4|5) ;;
         *) usage; exit 1 ;;
esac

Any way too make him pass more than 2 arguments?... and he's probably counting the -c as one.

It would help if you show the script. How are you executing this? What is the command you send over to the server. Since you didn't supply the script I created x.sh that just outputs argument count, arguments...

echo $# 
echo $* 
exit

I didn't have problems with argument counting. This works....

[josephgr@oc0887178221 ~]$ ssh josephgr@freezer1 ./x.sh  "-i 275.30.44.55 -n WYWYOU"
josephgr@freezer1's password: 
4
-i 275.30.44.55 -n WYWYOU
1 Like

Thanks for the anwser but the real problem is the script is actually the remote user login shell which is in the home of the remote user.

  • serverA ssh serverB with user1
  • user1 login shell is x.sh
  • user1's home on serverB contains x.sh which gets exec upond login.
  • can't pass args too that exec via ssh

Keys are handle and scripts exec is handle too. Only params poses a problem. Hope it is clearer (been banging my head on that since Friday).

What are the contents of x.sh? If it's mangling arguments, it will have to be worked around, and one can hardly tell that without knowing what it is.

1 Like

Yes, "-c" is one argument and the rest is the second. Your problem is not the passing of the parameters but the splitting of them.

You could emulate the splitting along IFS characters inside your shell this way:

#! /bin/ksh
args="$1"
IFS=" "
while : ; do
     print - "next: ${args%%${IFS}*}"
     if [ "$args" != "${args#*${IFS}}" ] ; then
          args="${args#*${IFS}}"
          print - "rest: $args"
     else
          print - "rest:"
          break
     fi
done

When run it looks like this:

# ./split.ksh 'a     b c def g h'
next: a
rest:     b c def g h
next: 
rest:    b c def g h
next: 
rest:   b c def g h
next: 
rest:  b c def g h
next: 
rest: b c def g h
next: b
rest: c def g h
next: c
rest: def g h
next: def
rest: g h
next: g
rest: h
next: h
rest:

Notice that you will have to throw out empty "args" in the loop to compensate for multiple consecutive IFS chars.

I hope this helps.

bakunin

1 Like

Ohhhh i get it now... Yeah well like you guys said the problem will be the parsing.

For the script it is a script that edit's a dns file and relaunches the process.

$ insert_host_ip.bash -i <ip> -n <name record> [-d] (to delete the record)

So basicly the args are "-i" "-n" "ip address" "name_record" "-D"

Nothing with spaces or weird chars but i do parse my options with a basic getops

# Parse the arguments
while getopts i:n:R OPTION; do
  case "$OPTION" in
        D) REMOVE=Y
        ;;
        i) IP_ADDRESS=$OPTARG
        ;;
        n) NAME_RECORD=$OPTARG
        ;;
        :) usage ; exit 5
        ;;
        \?) usage ; exit 5
        ;;
  esac
done

shift $((OPTIND-1))

No, I mean -- what are the contents of x.sh? The shell script that gets executed on login?

1 Like

Its a simple script that take an IP and NAME_RECORD and update a dns file. Relaunches named after the change.

Thing is the user1 CANNOT have a valid login shell so the remote script acts as a login shell

usage () {
        cat >&2 <<EOF

Insert/delete IP addresses and name records
in hosts DNS.
OS: RHEL 5.5

Usage: ${0##*/} -i \$IP_ADDRESS -n \$NAME_RECORD [ -D optional ]

- Default is to Insert
- D switch to Delete

EOF

Sorry for the confusion but i took the name x.sh from blackrageous to simplify the example. the real script name is insert_host_ip_named.bash

I don't understand how that script could possibly do anything, at all, ever. It's nothing but a here-document.

Less jokingly, post the complete script please, my crystal ball is not functioning today :wink:

1 Like

Ok you asked for it :slight_smile:

#!/bin/bash

#  Name: Eric
#  Version: 1.0
#  Date: 17/02/2014

CONFIG_FILE=/home/user1/hosts.unix-int
BACKUP_DIR=/home/user1/backup
LOG_PATH=/home/user1/log
LOG_FILE="user1_dns_${DATE}.log"
DATE=$(date +%Y%m%d)

# Default is to add record
REMOVE=N

# Usage
usage () {
        cat >&2 <<EOF

Insert/delete IP addresses and name records
in hosts DNS.
OS: RHEL 5.5

Usage: ${0##*/} -i \$IP_ADDRESS -n \$NAME_RECORD [ -D optional ]

- Default is to Insert
- D switch to Delete

EOF
}

# Manage error
error_log () {
        printf "[ $1 ]: %-30s\n" "$2" | tee -a $LOG_PATH/$LOG_FILE
}

# Validate if param are ok
validate_params () {
        results=$(echo $IP_ADDRESS | awk --re-interval -F"." '$0 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}$/ && $1 <=255 && $2 <= 255 && $3 <= 255 && $4 <= 255 {print}')
}

# Validate if inside cloud
validate_cloud () {
        awk '/####START/,/####FIN_CLOUD/{print}' $CONFIG_FILE | egrep -q '${IP_ADDRESS}|${NAME_RECORD}'
}

# Search for existing ip in configuration file
search_existant_ip () {
        grep -q "^${IP_ADDRESS}" $CONFIG_FILE
}

# Search for existing host in configuration file
search_existant_host () {
        grep -q "${NAME_RECORD}" $CONFIG_FILE
}

# Manage backups of host file
backup_host_file () {
        if [ ! -d $BACKUP_DIR ]; then
                mkdir $BACKUP_DIR
        fi
        cp -p $CONFIG_FILE "${CONFIG_FILE}.$DATE"
}

# Do the modification to the host file
add_host () {
        sed -i "/####FIN_CLOUD/i $IP_ADDRESS\t$NAME_RECORD" $CONFIG_FILE
        search_existant_ip
        if [[ $? -eq 1 ]]; then
                error_log "ERROR" "IP not found after ADDING $IP_ADDRESS"
                exit 1
        fi
        search_existant_host
        if [[ $? -eq 1 ]]; then
                error_log "ERROR" "HOST not found after ADDING $NAME_RECORD"
                exit 1
        fi
        error_log "ADD" "$IP_ADDRESS - $NAME_RECORD"
}

remove_host () {
        validate_cloud
        if [[ $? -eq 1 ]]; then
                error_log "ERROR" "IP/HOST Found but outside cloud"
                exit 1
        fi
        sed -i "/^$IP_ADDRESS\t$NAME_RECORD/d" $CONFIG_FILE
        search_existant_ip
        if [[ $? -eq 0 ]]; then
                error_log "ERROR" "IP found after REMOVING $IP_ADDRESS"
                exit 1
        fi
        search_existant_host
                if [[ $? -eq 0 ]]; then
                error_log "ERROR" "HOST found after REMOVING $NAME_RECORD"
                exit 1
        fi
        error_log "REMOVE" "$IP_ADDRESS - $NAME_RECORD"
}

# Main

# Check number of arguments
case $# in
        4|5) ;;
        *) usage; exit 1 ;;
esac

# Parse the arguments
while getopts i:n:R OPTION; do
  case "$OPTION" in
        D) REMOVE=Y
        ;;
        i) IP_ADDRESS=$OPTARG
        ;;
        n) NAME_RECORD=$OPTARG
        ;;
        :) usage ; exit 5
        ;;
        \?) usage ; exit 5
        ;;
  esac
done

shift $((OPTIND-1))

# Validate params

validate_params $IP_ADDRESS
if [[ -z $results ]]; then
        error_log "ERROR" "Incorrect IP parameters"
        exit 5
fi

search_existant_ip
if [[ $? -eq '0' ]] && [[ $REMOVE == 'N' ]]; then
        error_log "ERROR" "Ip Address already exists in host file"
        exit 1
fi

search_existant_host
if [[ $? -eq '0' ]] && [[ $REMOVE == 'N' ]]; then
        error_log "ERROR" "Name record already exists in host file"
        exit 1
fi

backup_host_file
if [[ $? -eq '1' ]]; then
        error_log "ERROR" "Problem with backup copy"
        exit 1
fi
if [[ $REMOVE == 'Y' ]]; then
        search_existant_ip
        if [[ $? -eq '1' ]]; then
                error_log "ERROR" "Ip Address not in host file"
                exit 1
        fi
        search_existant_host
        if [[ $? -eq '1' ]]; then
                error_log "ERROR" "Host not in host file"
                exit 1
        fi
        remove_host
else
        add_host
fi

# Launch restart_named.sh

#service restart restart_named.sh
#/root/Restart_named.sh

exit 0

---------- Post updated at 06:07 PM ---------- Previous update was at 06:03 PM ----------

Food for thoughts....

I could probably skip the -n and -i cause these will be launched via a php page. So i could assume these will always be the same.

Then could i take $2 and put everything into an array and play with that to achieve the desire result?

I take it you're able to modify the contents of x.sh to your pleasing?

I automated a PHP page which grabbed data via ssh by reading text from stdin via read whenever an argument wasn't present. It worked like this:

if [ -z "$KEYNAME" ]
then
        echo "Input key name" >&2
        read KEYNAME
fi

# Lots and lots of checking code for a valid value of KEYNAME

This would let you drop the minimum-4-arguments requirement.

The >&2 was to print text to stderr and data to stdout, so the output of this script could be raw data.

1 Like

The script insert_host_ip_named.bash is mine but the webpage php code is not. I can give them what i want triggered but cannot modify the this flow:

User input info in php web page ----> that triggers from the http server the ssh to the named server which hosts the above script that modifies the dns files and relaunches named.

That is the full plan.

So the PHP page would not be triggering it via ssh?

Exactly the opposite .... the php page will trigger the ssh to the remote server.

You put in the info on the php page (those become args for my script).

The php code will trigger the ssh with the args

ServerA (php code, user input) --- launches the ssh with args --- ServerB receive the ssh with args and trigger upon login my above script with the correct args.

That's how my scheme works too. The php page writes into the connection, the script reads it, and it gets the variables that way.

1 Like

So how do you parse the data at the other end? The receiving part is my problem since i get 2 args (-c and a block of "-i 0.0.0.0 -n host1 ).

Should i drop the options since only the php code will trigger that script so no sense in keeping those?

Then i can put the block of args split it into an array and check check more check and then use the values?

As I explained, I don't use args. I write it into the script's standard input.

1 Like

Ohhhhhh f... me .... i'll take a look again tomorrow morning :slight_smile: Not sure if i'll be able to make it work the first time but i'll do my best :smiley:

Thanks alot for your help. I'll keep ya posted.

---------- Post updated 04-01-14 at 12:11 PM ---------- Previous update was 03-31-14 at 09:24 PM ----------

Ok round 2 :slight_smile:

I've looked at your method and mine just want to be sure about the work flow cause i'm still confused.

My method. Or at least what was the original plan:

  • User gets to a web page with a form asking for information (ip, host, remove or not).

  • He put's all the required info and push send.

  • The php code opens up a remote ssh connection (with remote server ip address of server plus credentials).

  • That login trigger the login shell which is my bash script. That runs with the desire arguments that comes from the ssh args.

That is the way i see it.

In my head your method goes like this.

  • PHP web page trigger the ssh connection which opens up the login shell script on the remote server and asks for information. Script is now open so it takes stdin info that the user provides and uses them to run the script.

Is that correct or am i far left field in lalaland?

Wouldn't it work to use set -- $2 in your script, given the positional parameters are as given in post#1?

I haven't tried but that was said a little bit before. I think it should work if i split the $2 correctly.