/* This file is part of "sshpass", a tool for batch running password ssh authentication
* Copyright (C) 2006 Lingnu Open Source Consulting Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version, provided that it was accepted by
* Lingnu Open Source Consulting Ltd. as an acceptable license for its
* projects. Consult http://www.lingnu.com/licenses.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#if HAVE_TERMIOS_H
#include <termios.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
enum program_return_codes {
RETURN_NOERROR,
RETURN_INVALID_ARGUMENTS,
RETURN_CONFLICTING_ARGUMENTS,
RETURN_RUNTIME_ERROR,
RETURN_PARSE_ERRROR,
RETURN_INCORRECT_PASSWORD,
RETURN_HOST_KEY_UNKNOWN,
RETURN_HOST_KEY_CHANGED,
};
// Some systems don't define posix_openpt
#ifndef HAVE_POSIX_OPENPT
int
posix_openpt(int flags)
{
return open("/dev/ptmx", flags);
}
#endif
int runprogram( int argc, char *argv[] );
struct {
enum { PWT_STDIN, PWT_FILE, PWT_FD, PWT_PASS } pwtype;
union {
const char *filename;
int fd;
const char *password;
} pwsrc;
} args;
static void show_help()
{
printf("Usage: " PACKAGE_NAME " [-f|-d|-p|-e] [-hV] command parameters\n"
" -f filename Take password to use from file\n"
" -d number Use number as file descriptor for getting password\n"
" -p password Provide password as argument (security unwise)\n"
" -e Password is passed as env-var \"SSHPASS\"\n"
" With no parameters - password will be taken from stdin\n\n"
" -h Show help (this screen)\n"
" -V Print version information\n"
"At most one of -f, -d, -p or -e should be used\n");
}
// Parse the command line. Fill in the "args" global struct with the results. Return argv offset
// on success, and a negative number on failure
static int parse_options( int argc, char *argv[] )
{
int error=-1;
int opt;
// Set the default password source to stdin
args.pwtype=PWT_STDIN;
args.pwsrc.fd=0;
#define VIRGIN_PWTYPE if( args.pwtype!=PWT_STDIN ) { \
fprintf(stderr, "Conflicting password source\n"); \
error=RETURN_CONFLICTING_ARGUMENTS; }
while( (opt=getopt(argc, argv, "+f:d:p:heV"))!=-1 && error==-1 ) {
switch( opt ) {
case 'f':
// Password should come from a file
VIRGIN_PWTYPE;
args.pwtype=PWT_FILE;
args.pwsrc.filename=optarg;
break;
case 'd':
// Password should come from an open file descriptor
VIRGIN_PWTYPE;
args.pwtype=PWT_FD;
args.pwsrc.fd=atoi(optarg);
break;
case 'p':
// Password is given on the command line
VIRGIN_PWTYPE;
args.pwtype=PWT_PASS;
args.pwsrc.password=strdup(optarg);
// Hide the original password from the command line
{
int i;
for( i=0; optarg[i]!='\0'; ++i )
optarg[i]='z';
}
break;
case 'e':
VIRGIN_PWTYPE;
args.pwtype=PWT_PASS;
args.pwsrc.password=getenv("SSHPASS");
if( args.pwsrc.password==NULL ) {
fprintf(stderr, "sshpass: -e option given but SSHPASS environment variable not set\n");
error=RETURN_INVALID_ARGUMENTS;
}
break;
case '?':
case ':':
error=RETURN_INVALID_ARGUMENTS;
break;
case 'h':
error=RETURN_NOERROR;
break;
case 'V':
printf("%s (C) 2006-2011 Lingnu Open Source Consulting Ltd.\n"
"This program is free software, and can be distributed under the terms of the GPL\n"
"See the COPYING file for more information.\n", PACKAGE_STRING );
exit(0);
break;
}
}
if( error>=0 )
return -(error+1);
else
return optind;
}
int main( int argc, char *argv[] )
{
int opt_offset=parse_options( argc, argv );
if( opt_offset<0 ) {
// There was some error
show_help();
return -(opt_offset+1); // -1 becomes 0, -2 becomes 1 etc.
}
if( argc-opt_offset<1 ) {
show_help();
return 0;
}
return runprogram( argc-opt_offset, argv+opt_offset );
}
int handleoutput( int fd );
/* Global variables so that this information be shared with the signal handler */
static int ourtty; // Our own tty
static int masterpt;
void window_resize_handler(int signum);
void sigchld_handler(int signum);
int runprogram( int argc, char *argv[] )
{
struct winsize ttysize; // The size of our tty
// We need to interrupt a select with a SIGCHLD. In order to do so, we need a SIGCHLD handler
signal( SIGCHLD,sigchld_handler );
// Create a pseudo terminal for our process
masterpt=posix_openpt(O_RDWR);
if( masterpt==-1 ) {
perror("Failed to get a pseudo terminal");
return RETURN_RUNTIME_ERROR;
}
fcntl(masterpt, F_SETFL, O_NONBLOCK);
if( grantpt( masterpt )!=0 ) {
perror("Failed to change pseudo terminal's permission");
return RETURN_RUNTIME_ERROR;
}
if( unlockpt( masterpt )!=0 ) {
perror("Failed to unlock pseudo terminal");
return RETURN_RUNTIME_ERROR;
}
ourtty=open("/dev/tty", 0);
if( ourtty!=-1 && ioctl( ourtty, TIOCGWINSZ, &ttysize )==0 ) {
signal(SIGWINCH, window_resize_handler);
ioctl( masterpt, TIOCSWINSZ, &ttysize );
}
const char *name=ptsname(masterpt);
int slavept;
/*
Comment no. 3.14159
This comment documents the history of code.
We need to open the slavept inside the child process, after "setsid", so that it becomes the controlling
TTY for the process. We do not, otherwise, need the file descriptor open. The original approach was to
close the fd immediately after, as it is no longer needed.
It turns out that (at least) the Linux kernel considers a master ptty fd that has no open slave fds
to be unused, and causes "select" to return with "error on fd". The subsequent read would fail, causing us
to go into an infinite loop. This is a bug in the kernel, as the fact that a master ptty fd has no slaves
is not a permenant problem. As long as processes exist that have the slave end as their controlling TTYs,
new slave fds can be created by opening /dev/tty, which is exactly what ssh is, in fact, doing.
Our attempt at solving this problem, then, was to have the child process not close its end of the slave
ptty fd. We do, essentially, leak this fd, but this was a small price to pay. This worked great up until
openssh version 5.6.
Openssh version 5.6 looks at all of its open file descriptors, and closes any that it does not know what
they are for. While entirely within its prerogative, this breaks our fix, causing sshpass to either
hang, or do the infinite loop again.
Our solution is to keep the slave end open in both parent AND child, at least until the handshake is
complete, at which point we no longer need to monitor the TTY anyways.
*/
int childpid=fork();
if( childpid==0 ) {
// Child
// Detach us from the current TTY
setsid();
// This line makes the ptty
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
sshpass-1.05.tar.gz (17个子文件)
sshpass-1.05
sshpass.1 5KB
AUTHORS 700B
COPYING 18KB
aclocal.m4 34KB
INSTALL 15KB
install-sh 13KB
Makefile.am 145B
configure 197KB
missing 11KB
depcomp 18KB
config.h.in 4KB
NEWS 213B
configure.ac 865B
Makefile.in 22KB
README 0B
ChangeLog 1KB
main.c 13KB
共 17 条
- 1
资源评论
- ziyueluo2013-03-06可以用,非常不错
- chhcneu2015-01-21挺不错的吧。不过我后来还是没有用上。
- catyao2013-06-19ssh神级别的自动工具,非常不错
胖次在哪里
- 粉丝: 27
- 资源: 22
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功