Detect output to tty - bash

I'm making a program to automatically type out the password when trying to ssh. The idea is I'll run my type_pass executable in the background and then start the ssh process. Something like
$ type_pass & ssh user#host.com
Currently this works as I've given a small delay (5 seconds) in the type_pass application it self.
type_pass looks something like
void typeout(int tofd, char* txt, int usecs = 100000) {
int len = strlen(txt);
for(int ii = 0; ii < len; ++ii) {
usleep(usecs);
int ioctlerr = ioctl(tofd, TIOCSTI, &txt[ii]);
int err = errno;
}
}
int main() {
sleep(10);
typeout(1, "asdas\n");
}
My question is how can I intelligently wait for the password prompt from the server and then start sending out the keys for the password?

Here's an expect script that I use for this purpose:
#!/usr/bin/expect
send_user "password: "
set old_timeout $timeout
set timeout -1
expect_user -re "(.*)\n"
send_user "\n"
set timeout $old_timeout
set password "$expect_out(1,string)\r"
spawn /bin/bash
interact {
-o -nobuffer "assword: " {
send $password
}
}
The above program asks the end user for the password and then stores it in the password variable. In this way, the password is never written to a file but expect will echo the output to the terminal. There is code that can be added to turn the echo off but I don't know it offhand.
Expect then launches a bash interactive shell.
From this point on, expect reviews all the output to the terminal. If a string is output that contains "assword:", expect will output the stored password variable.
By the way, I am not a fan of expect, but I find this program to be helpful in many cases including ssh.
I've also found sshpass to be helpful for your particular problem. I've also used ansible for similar work - but you have enough here to solve your problem.

Related

Shell script AT Commands : not able to send sms through serial port

I have the below shell script (expect) where I am trying to send SMS. I have referred many stack overflow references and found out that ctrl-z maps to \x1a. However, even after appending it to the message and sending to the port or sending ctrl z separately to the port didn't help me. It timeouts later.
The script is written to send sms in pdu format. Irrespective of that, I believe, this is a generic issue to send ctrl-z to port. If you feel the script has some other errors, please share the solution for the same.
Also the length (34) mentioned below is the length of the (PDU_LENGTH -2)/2 as per the specification. This length doesn't include ctrl-z character.
at_command = "AT+CMGS=34\r"
message_content = "0011000C810056890......"
Script:
set PROMPT "0"
set timeout "$COMMAND_TIMEOUT"
send "$at_command"
expect {
"OK" { puts "Command Accepted\n"; }
"ERROR" { puts "Command Failed\n"; }
timeout { puts "Unable to connect to $HOSTIP at $HOSTPORT"; exit 1 }
"*>*" { set PROMPT "1"; }
}
if { "$PROMPT" == "1" } {
send "$message_content"
send "\x1a"
expect {
"OK" { puts "\nCommand accepted"; }
"ERROR" { puts "\nCommand failed"; }
"*>*" { puts "CTRL-Z dint reach UT. Error..."; }
"*" { puts "Unexpected return value received"; }
}
}
Am very sure the script sends $message_content" to port but exits immediately after sending "$message_content".
OUTPUT:
AT+CMGS=34
>
I did something like this in c# with an SMS-Gateway-Modul.
I had to switch to PDU-Mode first!
After that i had to transmit the expected PDU-Length and finally the PDU itself.
Every command has to be committed with can carriage return ASC[13] and the PDU had to be committed with an ASC[26] finally.
Here you can see a schematic(!) flow, how i did it in c#:
1) Create PDU and get length
int len;
var pdu = PDUGenerator.GetPdu(destination, message, "", out len);
2) Switch to PDUMode
SendToCom("AT+CMGF=0" + System.Convert.ToChar(13));
3) Announce message length
SendToCom("AT+CMGS=" + len + System.Convert.ToChar(13));
4) Send PDU and commit
SendToCom(pdu + System.Convert.ToChar(26));

expect fails when running proc inside proc

My script works fine (retrieves sftp prompt) when using one proc. But when I try to use proc inside proc, script gets stuck, and I do not know why.
Please do not refactor the code, that is not the point, I need to understand what is the issue here.
Working code:
proc sftp_connect {} {
set times 0;
set connection_retry 2
set timeout 1;
while { $times < $connection_retry } {
spawn sftp ${SFTP_USER}#${SFTP_SERVER}
expect {
timeout { puts "Connection timeout"; exit 1}
default {exit 2}
"*assword:*" {
send "${SFTP_PASSWORD}\n";
expect {
"sftp>" { puts "Connected"; set times [ expr $times+1]; exp_continue}
}
}
}
}
send "quit\r";
}
sftp_connect
Debug output:
expect: does "\r\nsftp> " (spawn_id exp5) match glob pattern "sftp>"? yes
But after moving send password into separate proc, expect does not retrieve sftp prompt anymore ("sftp>"):
proc sftp_send_password {} {
send "${SFTP_PASSWORD}\n";
expect {
"sftp>" { puts "Connected"; set times [ expr $times+1]; exp_continue}
}
}
proc sftp_connect {} {
set times 0;
set connection_retry 2
set timeout 1;
while { $times < $connection_retry } {
spawn sftp ${SFTP_USER}#${SFTP_SERVER}
expect {
timeout { puts "Connection timeout"; exit 1}
default {exit 2}
"*assword:*" { sftp_send_password }
}
}
send "quit\r";
}
sftp_connect
Debug output:
expect: does "" (spawn_id exp0) match glob pattern "sftp>"? yes
I don't have my copy of "Exploring Expect" handy, but I think you're running into a variable scoping issue. spawn invisibly sets a variable named spawn_id. When you call spawn in a proc, that variable is scoped only for that proc. Declare it as global:
proc sftp_connect {} {
global spawn_id
# ... rest is the same
}
I think you don't have to do the same thing in sftp_send_password because expect has a more forgiving scoping scheme than Tcl (if expect does not find a local variable, look in the global namespace).
Your sftp_send_password proc will not affect the times variable in sftp_connect though, due to the same variable scoping issue. I'd recommend
proc sftp_send_password {times_var} {
upvar 1 $times_var times ;# link this var to that in the caller
send "${SFTP_PASSWORD}\n";
expect {
"sftp>" { puts "Connected"; incr times; exp_continue}
}
# note use of `incr` instead of `expr`
}
And then the sftp_connect proc sends the times variable name:
sftp_send_password times
The following is from the expect's man page:
Expect takes a rather liberal view of scoping. In particular, variables read by commands specific to the Expect program will be sought first from
the local scope, and if not found, in the global scope. For example, this obviates the need to place global timeout in every procedure you write
that uses expect. On the other hand, variables written are always in the local scope (unless a global command has been issued). The most common
problem this causes is when spawn is executed in a procedure. Outside the procedure, spawn_id no longer exists, so the spawned process is no longer
accessible simply because of scoping. Add a global spawn_id to such a procedure.

D: executeShell on Windows to run another program not returning immediately

I'm using D as a scripting language for Windows 7 console stuff to automate boring tasks. One of my scripts (open.exe) is supposed to allow me to open stuff from the command line without me having to specify which program I use (I have a configuration file with this stuff). Now, I use executeShell to do this, and call something like start [name of program I want to use] [name of input file]. If I do this directly from the shell, it returns immediately, but if I do it using my D script, it doesn't return until the program that it opens is closed. What should I do to allow it to return immediately?
For reference purposes, this is the business logic of my script (the main method just does some argument parsing for piping purposes):
immutable path = "some//path//going//to//config//file.conf";
void process(string input) {
string extension = split(input,".")[1]; //get file extension from input
auto config = File(path,"r"); auto found = false;
while (!config.eof()){
auto line = chomp(config.readln());
if (line[0]!='#') { //skip comment lines
auto divided = split(line, ":");
if (divided[0] == extension) {
found = true;
auto command = "start " ~ divided[1] ~ " " ~ input;
auto result = executeShell(command);
//test for error code and output if necessary
writeln(result.output);
}
}
}
if (!found)
writeln("ERROR: Don't know how to open " ~ input);
}
From the top of the std.process documentation:
Execute and wait for completion, collect output - executeShell
The Windows start program spawns a process and exits immediately. D's executeShell does something else. If you'd like to spawn another program, use the appropriate functions: spawnProcess or spawnShell.

C - passing an unknown command into execvp()

I'm writing a fake shell, where I create a child process and then call execvp(). In the normal shell, when I enter an unknown command such as 'hello' it returns 'hello: Command not found.' However, when I pass hello into execvp(), it doesn't return any error by default and just continues running the rest of my program like nothing happened. What's the easiest way to find out if nothing was actually run? here's my code:
if(fork() == 0)
{
execvp(cmd, args);
}
else
{
int status = 0;
int corpse = wait(&status);
printf(Child %d exited with a status of %d\n", corpse, status);
}
I know that if corpse < 0, then it's an unknown command, but there are other conditions in my code not listed where I don't want to wait (such as if & is entered at the end of a command). Any suggestions?
All of the exec methods can return -1 if there was an error (errno is set appropriately). You aren't checking the result of execvp so if it fails, the rest of your program will continue executing. You could have something like this to prevent the rest of your program from executing:
if (execvp(cmd, args) == -1)
exit(EXIT_FAILURE);
You also want to check the result of fork() for <0.
You have two independent concerns.
1) is the return value of execvp. It shouldn't return. If it does there is a problem. Here's what I get execvp'ing a bad command. You don't want to wait if execvp fails. Always check the return values.
int res = execvp(argv[1], argv);
printf ("res is %i %s\n", res, strerror(errno));
// => res is -1 No such file or directory
2) The other concern is background processes and such. That's the job of a shell and you're going to need to figure out when your program should wait immediately and when you want to save the pid from fork and wait on it later.

How to trace a program from its very beginning without running it as root

I'm writing a tool that calls through to DTrace to trace the program that the user specifies.
If my tool uses dtrace -c to run the program as a subprocess of DTrace, not only can I not pass any arguments to the program, but the program runs with all the privileges of DTrace—that is, as root (I'm on Mac OS X). This makes certain things that should work break, and obviously makes a great many things that shouldn't work possible.
The other solution I know of is to start the program myself, pause it by sending it SIGSTOP, pass its PID to dtrace -p, then continue it by sending it SIGCONT. The problem is that either the program runs for a few seconds without being traced while DTrace gathers the symbol information or, if I sleep for a few seconds before continuing the process, DTrace complains that objc<pid>:<class>:<method>:entry matches no probes.
Is there a way that I can run the program under the user's account, not as root, but still have DTrace able to trace it from the beginning?
Something like sudo dtruss -f sudo -u <original username> <command> has worked for me, but I felt bad about it afterwards.
I filed a Radar bug about it and had it closed as a duplicate of #5108629.
Well, this is a bit old, but why not :-)..
I don't think there is a way to do this simply from command line, but as suggested, a simple launcher application, such as the following, would do it. The manual attaching could of course also be replaced with a few calls to libdtrace.
int main(int argc, char *argv[]) {
pid_t pid = fork();
if(pid == 0) {
setuid(123);
seteuid(123);
ptrace(PT_TRACE_ME, 0, NULL, 0);
execl("/bin/ls", "/bin/ls", NULL);
} else if(pid > 0) {
int status;
wait(&status);
printf("Process %d started. Attach now, and click enter.\n", pid);
getchar();
ptrace(PT_CONTINUE, pid, (caddr_t) 1, 0);
}
return 0;
}
This script takes the name of the executable (for an app this is the info.plist's CFBundleExecutable) you want to monitor to DTrace as a parameter (you can then launch the target app after this script is running):
string gTarget; /* the name of the target executable */
dtrace:::BEGIN
{
gTarget = $$1; /* get the target execname from 1st DTrace parameter */
/*
* Note: DTrace's execname is limited to 15 characters so if $$1 has more
* than 15 characters the simple string comparison "($$1 == execname)"
* will fail. We work around this by copying the parameter passed in $$1
* to gTarget and truncating that to 15 characters.
*/
gTarget[15] = 0; /* truncate to 15 bytes */
gTargetPID = -1; /* invalidate target pid */
}
/*
* capture target launch (success)
*/
proc:::exec-success
/
gTarget == execname
/
{
gTargetPID = pid;
}
/*
* detect when our target exits
*/
syscall::*exit:entry
/
pid == gTargetPID
/
{
gTargetPID = -1; /* invalidate target pid */
}
/*
* capture open arguments
*/
syscall::open*:entry
/
((pid == gTargetPID) || progenyof(gTargetPID))
/
{
self->arg0 = arg0;
self->arg1 = arg1;
}
/*
* track opens
*/
syscall::open*:return
/
((pid == gTargetPID) || progenyof(gTargetPID))
/
{
this->op_kind = ((self->arg1 & O_ACCMODE) == O_RDONLY) ? "READ" : "WRITE";
this->path0 = self->arg0 ? copyinstr(self->arg0) : "<nil>";
printf("open for %s: <%s> #%d",
this->op_kind,
this->path0,
arg0);
}
If the other answer doesn't work for you, can you run the program in gdb, break in main (or even earlier), get the pid, and start the script? I've tried that in the past and it seemed to work.
Create a launcher program that will wait for a signal of some sort (not necessarily a literal signal, just an indication that it's ready), then exec() your target. Now dtrace -p the launcher program, and once dtrace is up, let the launcher go.
dtruss has the -n option where you can specify name of process you want to trace, without starting it (Credit to latter part of #kenorb's answer at https://stackoverflow.com/a/11706251/970301). So something like the following should do it:
sudo dtruss -n "$program"
$program
There exists a tool darwin-debug that ships in Apple's CLT LLDB.framework which will spawn your program and pause it before it does anything. You then read the pid out of the unix socket you pass as an argument, and after attaching the debugger/dtrace you continue the process.
darwin-debug will exec itself into a child process <PROGRAM> that is
halted for debugging. It does this by using posix_spawn() along with
darwin specific posix_spawn flags that allows exec only (no fork), and
stop at the program entry point. Any program arguments <PROGRAM-ARG> are
passed on to the exec as the arguments for the new process. The current
environment will be passed to the new process unless the "--no-env"
option is used. A unix socket must be supplied using the
--unix-socket=<SOCKET> option so the calling program can handshake with
this process and get its process id.
See my answer on related question "How can get dtrace to run the traced command with non-root priviledges?" [sic].
Essentially, you can start a (non-root) background process which waits 1sec for DTrace to start up (sorry for race condition), and snoops the PID of that process.
sudo true && \
(sleep 1; cat /etc/hosts) &; \
sudo dtrace -n 'syscall:::entry /pid == $1/ {#[probefunc] = count();}' $! \
&& kill $!
Full explanation in linked answer.

Resources