Link to home
Start Free TrialLog in
Avatar of basant
basant

asked on

password from stdin through some C program.

I have an utility named setsqlnk
which takes verious input
as well as password.

This utility stores the information
read by the script in one ini file.
The password is stored in encrypted
manner.
I want to use this utility setsqlnk
from a C program. This means I want
to give the inputs through a file
and redirecting it to the stdin of the
utility.
i.e. setsqlnk < inpfilename

When I does so, it just escape the password entry.

Is there any mean to do so ? I mean can I run this utility through some other b/g process without entering the password from keyboard.

Thanks in advance.

Note : I don't think the utility is using
crypt command to encrypt the password.
OS : Linux 2.2.12-20
Avatar of rbr
rbr

use

FILE *pf;

pf=popen ("setsqlng < inpfilenne","r");

Now you can read the output of the programm setsqlng by using the FILE-pointer pf.

Avatar of basant

ASKER

Sorry rbr,
  Either u didn't read the question
properly or I was not able to explain my question properly.

Question is not that I was not able to read the output. The question is how will I pass the password to utility setsqlnk. The input redirection < 
works for other inputs but fails for the password entry.
Avatar of ozo
man pty
man expect
Avatar of basant

ASKER

Dear ozo, Thanks for telling about
the utility expect.
I tried the utility and run
the following commands :

spawn setsqlnk
send "2\n"
send "Trail3\n"
send "Trialjdf\n"
send "Hello\n"
send "1\n"
send "dev-31\n"
send "4\n"
send "sa\n"
send "hello\n"
send "12\n"
send "SLSocket\n"
send "sales-05\n"
send "0\n"
send "0\n"
exit

Note that "sa" is the username and
"hello" is the password. This worked when I tried this utility from command
line shell.
But when I tried to run the utility
by typing these commands in file and
running :
expect -f filename

I found out that my original program
setsqlnk is waiting on password itself.

Can u suggest something.
Meanwhile I am trying to use 'C' program
to do the same. Hope I get some success.
~
Avatar of basant

ASKER

Dear ozo, Thanks for telling about
the utility expect.
I tried the utility and run
the following commands :

spawn setsqlnk
send "2\n"
send "Trail3\n"
send "Trialjdf\n"
send "Hello\n"
send "1\n"
send "dev-31\n"
send "4\n"
send "sa\n"
send "hello\n"
send "12\n"
send "SLSocket\n"
send "sales-05\n"
send "0\n"
send "0\n"
exit

Note that "sa" is the username and
"hello" is the password. This worked when I tried this utility from command
line shell.
But when I tried to run the utility
by typing these commands in file and
running :
expect -f filename

I found out that my original program
setsqlnk is waiting on password itself.

Can u suggest something.
Meanwhile I am trying to use 'C' program
to do the same. Hope I get some success.
~
I don't think you've done your expect script correctly. My guess is that your program outputs a prompt and waits for an answer. If I had the following on the screen from an interactive program:

levie> gork
Username: mildred
Password: ******
levie>

I'd need an expect script that would look like:

#!/usr/local/bin/expect
# Interact with gork
#
spawn gork
expect "Username: "
send "mildred\r"
expect "Password: "
send "the-password\r"
send_user "\n"

Note that I send the data terminated by a carriage return, not a newline. That's what would have been sent if you were interacting directly.
Avatar of basant

ASKER

Dear Jlevie,
  Thanks for ur comment.
But as I wrote things works
when I use the expect utility in
command line and sends different strings one by one but when I try to send the same thing by typing the same commands in a file. The utility just
waits at the password.

Another point is :
At the time of asking passwords, the
echo remains off, similar to su
utility.

Any more comment is welcome.
Can u send me some 'C' source code of the expect utility. I mean can u tell where can I find that.
And the difference is that when you use expect from the command line you are sending a carriage return (\r), but in your script you told it to use a new-line (\n). They are not even close to being the same thing and the special mode the program is in when it's expecting the password cares which is used.
Avatar of basant

ASKER

But I used \n in both the command line
and in script. It worked in command line mode of except but it failed with filename of except. ( I mean except -f filename). I didn't use \r.

Can u please explain what is happening when I use redirection operator <.
Why does it skip password. I think this is certainly related with terminal i/o. We tried to trap system calls using strance.

This is the output from strace when I use redirection <. It shows that it calls ioctl with TCGETS option.

[pid  8536] write(1, "*Password[*****] :", 17) = 17
[pid  8536] _llseek(0, -27, 0xbfffe3e0, 0x4017c48c /* SEEK_??? */) = -1 EINVAL (Invalid argument)                               [pid  8536] ioctl(0, TCGETS, 0xbfffe314 ) = -1 EINVAL (Invalid argument)
[pid  8536] write(1, "\n", 1)           = 1

I might be off track with the \r, but other programs that I've had to script that required an interactive password (no echo, prints "*"s, typical stuff) won't take the password if it's terminated with a new-line, but will if it's terminated with "\r". Did you try using "\r's?

Okay as to input redirection with "<". The program is changing modes on its tty to turn off echo, etc. Since redirection is acutally a file and not a tty the I/O calls to set these modes aren't available and it fails.
Avatar of basant

ASKER

Dear jlevie, Thanks for ur comments.

There was not difference in \n and
in \r atleast in my case.
However I got a lot of success.
The problem was solved using sleep.

Actually before and after password,
I need to put sleep which result in
scheduling of actual utility setsql.

Also I used sleep 2; and interact; call to flush the output.

spawn setsqlnk; send "2\n";
send "Arbit1\n";
send "Trialjdf\n";
send "Hello\n";
send "1\n";
send "dev-31\n";
send "4\n";
send "sa\n";
sleep 2;
send "hello\n";
sleep 2;
send "12\n";
send "SLSocket\n";
send "sales-05\n";
send "0\n";
send "0\n";
sleep 2;
interact;
exit;


However this solution of using sleep
doesn't seems to be perfect. I need to use some of the wait calls to that process. Can u suggest that how to know that the process has read the inputs which expect has sent it.
Also before exit, it need to do the same
otherwise the utility just closes without completing the task.

I guess that "send" just copies the
data in the stdin of the process but
it don't wait for the other process to read it. That's why the things were working with command line and was not working with command file.
What is ur opinion.

I will grade this question soon.
ASKER CERTIFIED SOLUTION
Avatar of jlevie
jlevie

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
you probablly need an
expect «prompt»;
before the
send «password»
Avatar of basant

ASKER

Hi ozo and jlevie,

by using expect and wait internal commands of expect utility I have removed the two
sleep statements. So my new Code is like this :


spawn setsqlnk;
send "2\n";
send "Arbit9\n";
send "Trialjdf\n";
send "Hello\n";
send "1\n";
send "dev-31\n";
send "4\n";
expect "User"
send "sa\n";
expect -ex "Password\[*****\]:"
sleep 2;
send "hello\n";
expect "The following service"
send "12\n";
expect "Name"
send "SLSocket\n";
send "sales-05\n";
expect "Select an action"
send "0\n";
wait;
exit;




but still if I remove the sleep statement my expect thing stops working and my setsqlnk utility remains still waiting for Password.

I am not able to understand that even though the expect got the prompt "Password[**]" Why should it give chance the utility setsqlnk to run ( this will be the result of sleep , I think so)
Getting closer... each of the "send somethings" in the script needs to be preceeded by an "expect something". The whole idea of expect is to exactly duplicate what you'd see and when you'd respond if you were running the utility interactively. I think that the program output on the screen looked something like:

User sa
Password ******

The expect script for that portion would look like:

expect "User "
send "sa\r"
expect "Password "
send "some-password\r"

Note that I'm not asking the expect program to wait for "Password ******". The prompt was "Password" and the "*****" were the hidden password you typed in.

Let's make this easy. If you'll run the program interactively and type into a comment exactly what you see on the screen, I'll write you an expect script that ought to work.
Avatar of basant

ASKER

Hi ozo and jlevie,

by using expect and wait internal commands of expect utility I have removed the two
sleep statements. So my new Code is like this :


spawn setsqlnk;
send "2\n";
send "Arbit9\n";
send "Trialjdf\n";
send "Hello\n";
send "1\n";
send "dev-31\n";
send "4\n";
expect "User"
send "sa\n";
expect -ex "Password\[*****\]:"
sleep 2;
send "hello\n";
expect "The following service"
send "12\n";
expect "Name"
send "SLSocket\n";
send "sales-05\n";
expect "Select an action"
send "0\n";
wait;
exit;




but still if I remove the sleep statement my expect thing stops working and my setsqlnk utility remains still waiting for Password.

I am not able to understand that even though the expect got the prompt "Password[**]" Why should it give chance the utility setsqlnk to run ( this will be the result of sleep , I think so)
Avatar of basant

ASKER

Dear jlevie,
  Sorry my comment reappeared as by mistake I set refresh scren in my browser which posted the comment again.
Sorry it happened twice.

Well Coming to the point :

See the trial shell script named inp:
#!/bin/sh
printf "\n Enter some value [**0]: "
stty -echo
read aVal
stty echo
printf "\n The Value is $aVal"
printf "\n"


If u want to run this shell script using expect :

spawn -noecho inp
expect -ex "some value \[**0\]:"
send_tty "\n Spawn Id is $spawn_id"
exp_pid -i $spawn_id
send "56\n";
expect "The Val" {
    stty -echo
}
send_tty "\n End of script\n"
exit;

This works fine but this is not the
case of with my orignal utility setsqlnk. This setsqlnk is a script which actually start a process which is an executable named sqlnkcau.


>Note that I'm not asking the expect >program to wait for "Password ******". >The prompt was "Password" and the >"*****" were the hidden password you >typed in.

I think, there is a communication gap here. When the executable asks for a password, it set the echo off similar to su command. No * appears when u really type the password.
However the string prompting for password is : "Password[*****]:" [ These * appears as a prompt, not when the user types.

Thus The command
expect -ex "Password\[*****\]:"
returns success immediately.
But without sleep after this prompt, it doesn't work. I don't understand why ?
Now I understand what's happening.

I've been thinking that setsqlnk was program (you called it a utility in the question). Now I find that it's not an actual program, but instead it's a shell script that gathers data and uses that data in the execution of an actual binary... That explains why you could get it to work with a sleep (gives the sqlnkcau time to start) and also exlains why everthing isn't synching up via the expect/send sequence.

Am I correct in assuming that it's sqlnkcau that prompts for the username & password? What else does setsqlnk do?

I can think of several ways to solve this, but to be able to offer a solution I probably need to know what setsqlnk does and what sqlnkcau does.
Avatar of basant

ASKER

I am sorry that I was not able to communicate the problem properly.

OK following is the setsqlnk shell script.

#!/bin/sh
if [ -f /opt/bk/casp/asp-apache-3476/odbc.ini ]; then
      . /opt/bk/casp/chsetup.sh
      . /opt/bk/casp/asp-apache-3476/odbc.sh

      cd /opt/bk/casp/odbc/sqlnk/bin
      ./sqlnkcau
else
      echo "setsqlnk: No odbc.ini found in /opt/bk/casp/asp-apache-3476."
fi


Thus this utility does not do much but run another shell script odbc.sh & chsetup.sh and then run the executable sqlnkcau.

Note that all the input reading comes from the executable , not the shell script including password.

These shell scripts only setup the envirionment e.g. proper env Variable setup like LD_LIBRARY_PATH and so.

Regarding ur comment :
>That explains why you could get it to >work with a sleep (gives the sqlnkcau >time to start) and also exlains why >everthing isn't synching up via the >expect/send sequence.

Well I do think that one can send many inputs simultaneously and then may expect for some inputs. Do u mean to say that my
expect -ex "Password\[*****\]:"
fails. If it is successful then the sqlnkcau has already written this string and now it is waiting for input in read system call. Amn't I correct.
Avatar of basant

ASKER

Dear jlevie,
   I tried to run the program sqlnkcau directly with expect even though the result is same. I mean it doesn't work without the sleep statement.
With sleep it works just perfect.
How about running sqlnkcau interactively (in a terminal window) and putting exactly what is on the screen into a comment so I can see it. I'd like to see everything from the shell prompt line where you execute sqlnkcau to the shell prompt after it is done, like:

user> sqlnkcau
....
.... lines of
.... ineraction
.... with sqlnkcau
....
user>
Avatar of basant

ASKER

I will post it soon.
Basant.
Avatar of basant

ASKER

Dear jlevie,
   I tried to write the 'C' program using libexpect there I used the same thing what I was doing in utility but even in 'C' programme, if I don't go for sleep, the same thing happens.

However I solved the problem by calling strace utility to the sqlnkcau. when strace utility shows that it is waiting at read then I kill the strace utility and then use expect and send and then it works.

Here is the partial code :

int WriteNewSQLDSN( vector<string>& vecCmds, const string& strDir)
{
      int fd1, fd2;
      char szBuf[80];

      exp_loguser = 1;
      exp_timeout = 3600;
      string strSetSqlnkPath= strDir;
      strSetSqlnkPath += "/setsqlnk";
      fd1 = exp_spawnl( (char*) strSetSqlnkPath.c_str() ,
                  "setsqlnk", (char*) 0 );
      cout << "\n pid = " << exp_pid;
      cout << "\n Enter the sqlcau pid :";
      int nActPid;
      //cin >> nActPid;
      /*
      char* pCmd[20] = {
                  "2\r",
                  "Arbit9\r",
                  "Trialjdf\r",
                  "Hello\r",
                  "1\r",
                  "dev-31\r",
                  "4\r",
                  "sa\r",
                  "hello\r\n",
                  "12\r",
                  "SLSocket\r",
                  "sales-05\r",
                  "0"
                  };
      */
      cout << "\n before expectl ";
      cout.flush();
      if (-1 == exp_expectl(fd1, exp_exact,"Select an action",0,
                        exp_end))      
      {
            cout << "\n exp_expectl failed ";
            cout.flush();
            return -1;
      }
      nActPid = ReadSqlcauPid();
      cout << "\n after expectl ";
      cout.flush();
      int nIndex = 0;
      for( nIndex = 0; nIndex < 7; ++nIndex)
      {
          if (-1 == write(fd1,vecCmds[nIndex].c_str() ,strlen(
                                    vecCmds[nIndex].c_str() ) ))
            {
                  cout << "\n write failed";
                  return -1;
            }
      }
      if (-1 == exp_expectl(fd1, exp_exact,"User",0,
                        exp_end))      
      {
            cout << "\n exp_expectl failed ";
            cout.flush();
            return -1;
      }
    if (-1 == write(fd1,vecCmds[nIndex].c_str() ,strlen(
                                    vecCmds[nIndex].c_str()) ))
      {
            cout << "\n write failed";
            return -1;
      }
      ++nIndex;

      if (-1 == exp_expectl(fd1, exp_exact,"Password[*****]:",0,
                        exp_end))      
      {
            cout << "\n exp_expectl failed ";
            cout.flush();
            return -1;
      }
      RunStrace( nActPid);
      cout << "\n After Password prompt";
      cout.flush();
    if (-1 == write(fd1,vecCmds[nIndex].c_str() ,strlen(
                  vecCmds[nIndex].c_str()) ))
      {
            cout << "\n write failed";
            return -1;
      }
      ++nIndex;
      cout << "\n After Password write";
      cout.flush();

      if (-1 == exp_expectl(fd1, exp_exact,"The following service", 0,
                        exp_end))      
      {
            cout << "\n exp_expectl failed ";
            cout.flush();
            return -1;
      }
      for( ; nIndex < 12; ++nIndex)
      {
          if (-1 == write(fd1,vecCmds[nIndex].c_str() ,strlen(
            vecCmds[nIndex].c_str()) ))
            {
                  cout << "\n write failed";
                  return -1;
            }
      }
      if (-1 == exp_expectl(fd1, exp_exact,"Select an action", 0,
                        exp_end))      
      {
            cout << "\n exp_expectl failed ";
            cout.flush();
            return -1;
      }
    if (-1 == write(fd1,vecCmds[nIndex].c_str() ,strlen(
                                    vecCmds[nIndex].c_str()) ))
      {
            cout << "\n write failed";
            return -1;
      }
      /*
      cout << "\n Enter some number :";
      int nNumber;
      cin >> nNumber;
      int n = read(fd1,szBuf,80);
      if( n > 0 )
      {
            szBuf[n]='\0';
            cout << "Output = " <<szBuf;
      }
      */
      cout << "\n End of Program";
return 0;      
}

main()
{
      string strDir = "/opt/bk/casp/asp-apache-3476";
      char* pCmd[20] = {
                  "2\r",
                  "Arbit9\r",
                  "Trialjdf\r",
                  "Hello\r",
                  "1\r",
                  "dev-31\r",
                  "4\r",
                  "sa\r",
                  "hello\r\n",
                  "12\r",
                  "SLSocket\r",
                  "sales-05\r",
                  "0"
                  };
      int nNoOfArg = 13;
      int nIndex = 0;
      vector<string> vecArgs( nNoOfArg );
      for( nIndex = 0; nIndex < nNoOfArg; ++nIndex)
      {
            vecArgs[nIndex] = pCmd[nIndex];
      }
      WriteNewSQLDSN( vecArgs, strDir) ;
}



Anyway I should give points to u. If u have something to comment then u can write.