1
/* This file is part of "sshpass", a tool for batch running password ssh authentication
2
* Copyright (C) 2006 Lingnu Open Source Consulting Ltd.
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version, provided that it was accepted by
8
* Lingnu Open Source Consulting Ltd. as an acceptable license for its
9
* projects. Consult http://www.lingnu.com/licenses.html
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
#include <sys/types.h>
29
#include <sys/ioctl.h>
30
#include <sys/select.h>
34
//#include <asm/ioctls.h>
41
int runprogram( int argc, char *argv[] );
44
enum { PWT_STDIN, PWT_FILE, PWT_FD, PWT_PASS } pwtype;
52
static void show_help()
54
printf("Usage: " PACKAGE_NAME " -fdph command parameters\n"
55
" -f filename Take password to use from file\n"
56
" -d number Use number as file descriptor for getting password\n"
57
" -p password Provide password as argument (security unwise)\n"
58
" -e Password is passed as env-var \"SSHPASS\"\n"
59
" With no parameters - password will be taken from stdin\n\n"
60
" -h Show help (this screen)\n"
61
" -V Print version information\n"
62
"At most one of -f, -d, -p or -e should be used\n");
65
// Parse the command line. Fill in the "args" global struct with the results. Return argv offset
66
// on success, and a negative number on failure
67
static int parse_options( int argc, char *argv[] )
72
// Set the default password source to stdin
73
args.pwtype=PWT_STDIN;
76
#define VIRGIN_PWTYPE if( args.pwtype!=PWT_STDIN ) { \
77
fprintf(stderr, "Conflicting password source\n"); \
80
while( (opt=getopt(argc, argv, "+f:d:p:heV"))!=-1 && error==0 ) {
83
// Password should come from a file
87
args.pwsrc.filename=optarg;
90
// Password should come from an open file descriptor
94
args.pwsrc.fd=atoi(optarg);
97
// Password is given on the command line
100
args.pwtype=PWT_PASS;
101
args.pwsrc.password=optarg;
106
args.pwtype=PWT_PASS;
107
args.pwsrc.password=getenv("SSHPASS");
117
printf("%s (C) 2006 Lingnu Open Source Consulting Ltd.\n"
118
"This program is free software, and can be distributed under the terms of the GPL\n"
119
"See the COPYING file for more information.\n", PACKAGE_STRING );
131
int main( int argc, char *argv[] )
133
int opt_offset=parse_options( argc, argv );
136
// There was some error
145
return runprogram( argc-opt_offset, argv+opt_offset );
148
int handleoutput( int fd );
150
int runprogram( int argc, char *argv[] )
152
// Create a pseudo terminal for our process
153
int masterpt=getpt();
156
perror("Failed to get a pseudo terminal");
161
if( grantpt( masterpt )!=0 ) {
162
perror("Failed to change pseudo terminal's permission");
166
if( unlockpt( masterpt )!=0 ) {
167
perror("Failed to unlock pseudo terminal");
176
// Detach us from the current TTY
179
const char *name=ptsname(masterpt);
180
int slavept=open(name, O_RDWR );
181
//fprintf(stderr, "Opened %s with fd %d\n", name, slavept);
184
char **new_argv=malloc(sizeof(char *)*(argc+1));
188
for( i=0; i<argc; ++i ) {
194
execvp( new_argv[0], new_argv );
196
perror("sshpass: Failed to run command");
199
} else if( childpid<0 ) {
200
perror("sshpass: Failed to create child process");
214
FD_SET(masterpt, &readfd);
216
int selret=select( masterpt+1, &readfd, NULL, NULL, NULL );
219
if( FD_ISSET( masterpt, &readfd ) ) {
220
if( handleoutput( masterpt ) ) {
221
// Authentication failed - need to abort
222
close( masterpt ); // Signal ssh that it's controlling TTY is now closed
223
terminate=255; // This is what openssh returns on authentication errors
227
wait_id=waitpid( childpid, &status, WNOHANG );
229
wait_id=waitpid( childpid, &status, 0 );
231
} while( wait_id==0 || (!WIFEXITED( status ) && !WIFSIGNALED( status )) );
235
else if( WIFEXITED( status ) )
236
return WEXITSTATUS(status);
241
int match( const char *reference, const char *buffer, ssize_t bufsize, int state );
242
void write_pass( int fd );
244
int handleoutput( int fd )
246
// We are looking for the string
247
static int prevmatch=0; // If the "password" prompt is repeated, we have the wrong password.
249
static const char compare[]="assword:";
253
int numread=read(fd, buffer, sizeof(buffer) );
255
state=match( compare, buffer, numread, state );
257
if( compare[state]=='\0' ) {
263
// Wrong password - terminate with proper error code
272
int match( const char *reference, const char *buffer, ssize_t bufsize, int state )
274
// This is a highly simplisic implementation. It's good enough for matching "Password: ", though.
276
for( i=0;reference[state]!='\0' && i<bufsize; ++i ) {
277
if( reference[state]==buffer[i] )
281
if( reference[state]==buffer[i] )
289
void write_pass_fd( int srcfd, int dstfd );
291
void write_pass( int fd )
293
switch( args.pwtype ) {
295
write_pass_fd( STDIN_FILENO, fd );
298
write_pass_fd( args.pwsrc.fd, fd );
302
int srcfd=open( args.pwsrc.filename, O_RDONLY );
304
write_pass_fd( srcfd, fd );
310
write( fd, args.pwsrc.password, strlen( args.pwsrc.password ) );
311
write( fd, "\n", 1 );
316
void write_pass_fd( int srcfd, int dstfd )
324
int numread=read( srcfd, buffer, sizeof(buffer) );
326
for( i=0; i<numread && !done; ++i ) {
327
if( buffer[i]!='\n' )
328
write( dstfd, buffer+i, 1 );
334
write( dstfd, "\n", 1 );