Controlling a child's stdin/stdout (not working with scp)

All,

Ok...so I know I *should* be able to control a process's stdin and stdout from the parent by creating pipes and then dup'ing them in the child. And, this works with all "normal" programs that I've tried. Unfortunately, I want to intercept the stdin/out of the scp application and it seems scp is actively refusing to allow me to. The code is:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main()
{
	char	usr[32];
	char	host[32];
	char	remote_path[64];
	char	local_path[64];
	
	int	outfd[2];
	int	infd[2];
	
	/* set usr/host/remote_path/local_path to something meaningful */
	
	/* create pipes for stdin/out to dup in the child */	
	
	pipe(outfd); /* Where the parent is going to write to */
	pipe(infd); /* From where parent is going to read */
	
	if(!fork())
	{
		char	cmd[1024];
		
		/* child, close stdin/out and use parent pipes instead */
			
		close(STDOUT_FILENO);
		close(STDIN_FILENO);
		
		dup2(outfd[0], STDIN_FILENO);
		dup2(infd[1], STDOUT_FILENO);
		
		/* close all pipe ends, needed end has been dup'd other end
		     is not needed */
		     
		close(outfd[0]);
		close(outfd[1]);
		close(infd[0]);
		close(infd[1]);
		
		/* execute scp */
		
		sprintf(cmd, "scp %s@%s:%s %s",
			usr, host, remote_path, local_path);
		
		return system(cmd);
	}

	/* parent */
	
	char input[100];
		
	close(outfd[0]); /* These are being used by the child */
	close(infd[1]);
	
	input[read(infd[0],input,100)] = 0; /* Read from child's stdout */
	
	printf("%s",input);

	/* once I can actually read/write to scp here, I'll have to determine if this is
	     the password prompt or the "add to host key file" prompt and respond
	     accordingly. */
	
	close(outfd[1]);
	close(infd[0]);
}

I know the code works if I use something other than scp, I can write and read to the pipes all day long and control the process as desired. But, it seems that scp is specifically figuring out what the controlling terminal of the process is and actively refusing to co-operate with my pipes.

I then thought maybe I could try to "disown" the terminal by calling "setsid()" right before invoking scp (and tried it right after the fork). Well, that "works," but then the stupid thing connects to my X server and pops up a box to ask for the password. Of course, preventing scp from asking me anything is the exact reason I want to control the standard in of the process so I can funnel the password in through there.

So...does any one have another idea how I can redirect stdin/stdout for this most difficult process? It seems I'll actually need to "hook into" the terminal directly since scp is "so smart." Indeed, I believe scp may be openning up its own connection to the terminal to get input and send output....

Thanks....

P.S. I know there is a better way to do this, like creating the ssh keys so scp never asks for passwords to begin with. Unfortunately, the environment where I'm trying to use this disallows this. They want us to enter passwords every time and this "stupid" rule is circumventing my ability to automate tasks through scp; of course ftp is also taboo. So...I want this "scp wrapper" to read my local password file and just pass it through so I can get back to my regularly scheduled automation. Otherwise, I'll have to enter the passwords again and again while the scripts run...and that's just...well...pointless.

Yes, it does, and no, it won't let you, and that's for a reason -- stored passwords are not only inherently dangerous but completely unnecessary. Use shared keys, that's what they're there for. There's instructions for them plastered all over the internet and you can use them in ways that obey the spirit and letter of that rule -- give the shared key a password and use ssh-agent. That way you need to type the password once, to get the key, after which you can use the key to login automatically until your ssh-agent session finishes.

scp, sftp, and ssh are specifically engineered to stop what you are trying to do.
Corona is being kind. If you do not want to create ssh keys, then use ftp or commands like rcp. Don't make something insecure out of something that works hard to be secure.

Corona: There are 50+ hosts that this script needs to transfer files to/from. Each host has a different user/password. That user is the only one with access to the files I need to remote copy (besides root, of course). Can shared keys help here? The way I understand it, shared keys allow one user access to several hosts. They are tied to the user id. That won't help if this is true.

Jim: ftp/rcp are blocked, they aren't secure. Of course, neither is a password dictionary; but if you knew our password policy (and read above about the number of accounts all with disparite passwords), you'd realize everyone keeps them anyway. So...our security policy is so secure that it's insecure, lol. I'd just be making life easier if I could make this work.

You generate one key only - on the box you intend to do all the connections from.
Place the public key on all 50 remote boxes. Voila! ssh anyboxinthelist or sftp anyboxinthelist works magically. No passwords required.

Hereis how to do it:
ssh-keygen: password-less SSH login

Oh & when you are generating the key DO NOT enter any passphrase, just press return.

I got that, but I still don't see anything that says this works for multiple accounts. So, if I'm logged in to box1 as "dreamwarrior" and do the ssh-keygen, then I put the key file on box2 and try to do: "ssh user1@box2" it won't see "dreamwarrior's" key. Or am I misunderstanding something here? Can I put the "dreamwarrior" key on box2 in a location that allows ssh for ANY user? I would love it if "ssh box2" as dreamwarrior would work, but the fact is the "dreamwarrior" account on box2 won't have access to the "user1" files I need, so the scp will fail for permissions.

You put your dreasmwarrior key into the directory (.ssh) for the user you want to be. e.g., whoever.
then

ssh whoever@remotebox
#or
sftp whoever@anotherbox

You are now whoever, not dreamwarrior, on the remote box. So all you have to keep straight is what username goes with what remote box.

Ahh...well, that's the part that I wasn't getting. I didn't realize that would work. I'm an SA n00b for sure, lol! THANKS! I suppose the upfront work may be annoying, but at least it'll only have to be done once!

Much appreciated, and yes I agree, this is a much better solution than my hacking away supposing they'll let me do it. They may still say "well, if your dreamwarrior account gets hacked then the hacker has access to everything now...don't they." In which case, I suppose I can use the passphrase on the key and at least (according to Corona) I should only have to enter the passphrase once to enable the key and never again. Then there's another level of security.

The trick is you need to run ssh-agent, export the variables it gives you, then run ssh-add, at which point it will ask you for the password for your key. Once that's done, you'll be able to ssh, sftp, or scp into anything that accepts that key without a password until you kill that instance of ssh-agent. I login in the morning, enter the password once, do any remote stuff without any further passwords prompts, then kill the agent and logout at the end of the day :slight_smile:

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-jDJEL19095/agent.19095; export SSH_AUTH_SOCK;
SSH_AGENT_PID=19096; export SSH_AGENT_PID;
echo Agent pid 19096;
$ SSH_AUTH_SOCK=/tmp/ssh-jDJEL19095/agent.19095; export SSH_AUTH_SOCK;
$ SSH_AGENT_PID=19096; export SSH_AGENT_PID;
$ ssh-add
Enter passphrase for /home/xyz/.ssh/id_dsa:
Identity added: /home/xyz/.ssh/id_dsa (/home/xyz/.ssh/id_dsa)
$ ssh anemone
Last login: Thu Mar 11 16:01:39 CST 2010 from mecgentoo.vpn on ssh
Last login: Fri Mar 12 16:57:17 2010 from mecgentoo.vpn
xyz@anemone ~ $

If you need to login to one remote machine from another remote machine, it can even forward ssh-agent from one machine to another if you use ssh -A.

Thanks for all the info! Much appreciated....