Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,15 @@ config.status
*.o
sshpass
stamp-h1
INSTALL
Makefile.in
aclocal.m4
autom4te.cache/
compile
config.guess
config.h.in
config.sub
configure
depcomp
install-sh
missing
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,44 @@ For ssh servers with 2FA, with a normal password and time-based one time passwor

## Usage

Create a file containing your ssh password. ex: `~/.ssh/pw`
Create a file containing your ssh password, ex: `~/.ssh/pw` or better, create a command, ex: `~/.ssh/pwd`, that
prints the password after having it safely obtained from a password manager, like 1Password.

Create an shell executable file printing your One time password. ex: `~/.ssh/totp`
Create a command that prints your password using the 1Password CLI, ex: `~/.ssh/pwd`:

```shell=1
#!/bin/sh

op read op://Private/my-account/password
```

Create a command that prints your One Time Password, ex: `~/.ssh/totp`:

```shell=1
#!/bin/sh

oathtool --totp -b YOUR-SECRET-KEY
```
```

or using 1Password CLI:

```shell=1
#!/bin/sh

op read op://Private/my-account/one-time\ password?attribute=otp
```

Remember setting executable bit:

```
chmod +x ~/.ssh/pwd
chmod +x ~/.ssh/totp
```

Run sshpass with -f and -c parameters:
Run sshpass with -x and -c parameters:

```
sshpass -f ~/.ssh/pw -c ~/.ssh/totp ssh your-ssh-server
sshpass -x ~/.ssh/pwd -c ~/.ssh/totp ssh your-ssh-server
```

You can use -v parameter if something wrong.
Expand All @@ -36,7 +54,7 @@ You can use sshpass and ssh as a proxy command for connecting beyond severs. Edi

```
Host beyond
ProxyCommand sshpass -f ~/.ssh/pw -c ~/.ssh/totp ssh bastion -qW %h:%p
ProxyCommand sshpass -x ~/.ssh/pwd -c ~/.ssh/totp ssh bastion -qW %h:%p
```

Then run ssh.
Expand All @@ -51,12 +69,13 @@ ssh beyond
Added parameters:

```
-x command executable file name printing the password
-o OTP One time password
-c command executable file name printing one time password
-O OTP prompt Which string should sshpass search for the one time password prompt
```

-O option's default is `Verification code:`.
`-O` option's default is `Verification code:`.


## Build
Expand Down
48 changes: 45 additions & 3 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum program_return_codes {
RETURN_HOST_KEY_CHANGED,
RETURN_INCORRECT_OTP,
RETURN_OTP_COMMAND_ERROR,
RETURN_PWT_COMMAND_ERROR
};

// Some systems don't define posix_openpt
Expand All @@ -63,6 +64,7 @@ posix_openpt(int flags)
}
#endif

void run_pw_command();
void run_otp_command();
int runprogram( int argc, char *argv[] );
void reliable_write( int fd, const void *data, size_t size );
Expand All @@ -75,11 +77,12 @@ void write_pass( int fd );
void write_otp( int fd );

struct {
enum { PWT_STDIN, PWT_FILE, PWT_FD, PWT_PASS } pwtype;
enum { PWT_STDIN, PWT_FILE, PWT_FD, PWT_COMMAND, PWT_PASS } pwtype;
union {
const char *filename;
int fd;
const char *password;
const char *pwcommand;
} pwsrc;

const char *pwprompt;
Expand All @@ -97,6 +100,7 @@ static void show_help()
" -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"
" -x command executable file name printing password\n"
" -e Password is passed as env-var \"SSHPASS\"\n"
" With no parameters - password will be taken from stdin\n\n"
" -P prompt Which string should sshpass search for to detect a password prompt\n"
Expand All @@ -106,7 +110,7 @@ static void show_help()
" -o OTP One time password\n"
" -c command executable file name printing one time password\n"
" -O OTP prompt Which string should sshpass search for the one time password prompt\n"
"At most one of -f, -d, -p or -e should be used\n");
"At most one of -f, -d, -p, -x or -e should be used\n");
}

// Parse the command line. Fill in the "args" global struct with the results. Return argv offset
Expand All @@ -132,7 +136,7 @@ static int parse_options( int argc, char *argv[] )
optarg[i]='z'; \
} while(0)

while( (opt=getopt(argc, argv, "+f:d:p:P:o:c:O:heVv"))!=-1 && error==-1 ) {
while( (opt=getopt(argc, argv, "+f:d:p:x:P:o:c:O:heVv"))!=-1 && error==-1 ) {
switch( opt ) {
case 'f':
// Password should come from a file
Expand Down Expand Up @@ -163,6 +167,13 @@ static int parse_options( int argc, char *argv[] )
for( i=0; optarg[i]!='\0'; ++i )
optarg[i]='z';
}
break;
case 'x':
// Password is provided by command
VIRGIN_PWTYPE;
args.pwtype=PWT_COMMAND;
args.pwsrc.pwcommand=strdup(optarg);
HIDE_OPTARG;
break;
case 'P':
args.pwprompt=optarg;
Expand Down Expand Up @@ -249,6 +260,10 @@ int main( int argc, char *argv[] )
}
}

if( args.pwtype == PWT_COMMAND ) {
run_pw_command();
}

if( args.otptype == OTP_COMMAND ) {
run_otp_command();
}
Expand Down Expand Up @@ -580,6 +595,7 @@ void write_pass( int fd )
}
break;
case PWT_PASS:
case PWT_COMMAND:
reliable_write( fd, args.pwsrc.password, strlen( args.pwsrc.password ) );
reliable_write( fd, "\n", 1 );
break;
Expand Down Expand Up @@ -682,3 +698,29 @@ void run_otp_command()

pclose( fp );
}

void run_pw_command()
{
if( args.verbose ) {
fprintf(stderr, "SSHPASS popen(%s)\n", args.pwsrc.pwcommand);
}

FILE *fp = popen( args.pwsrc.pwcommand, "r" );
if( fp == NULL ) {
if( args.verbose ) {
perror( args.pwsrc.pwcommand );
}
exit(RETURN_PWT_COMMAND_ERROR);
}

char buf[256];
if( fgets( buf, sizeof(buf), fp ) != NULL ) {
char *p = strchr(buf, '\n');
if( p != NULL ) {
*p='\0';
}
args.pwsrc.password = strdup(buf);
}

pclose( fp );
}
27 changes: 22 additions & 5 deletions sshpass.1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
sshpass \- noninteractive ssh password provider
.SH SYNOPSIS
.B sshpass
.RB [ -f\fIfilename | -d\fInum | -p\fIpassword | -e ]
.RB [ -f \fIfilename | -d \fInum | -p \fIpassword | -x \fIcommand | -e ] [ -o \fIotp | -c \fIcommand ]
.RI [ options ] " command arguments"
.br
.SH DESCRIPTION
Expand All @@ -24,27 +24,44 @@ prompt used by ssh is, however, currently hardcoded into sshpass.
If no option is given, sshpass reads the password from the standard input. The
user may give at most one alternative source for the password:
.TP
.B \-p\fIpassword\fP
.B \-p \fIpassword\fP
The password is given on the command line. Please note the section titled
"\fBSECURITY CONSIDERATIONS\fP".
.TP
.B \-f\fIfilename\fP
.B \-f \fIfilename\fP
The password is the first line of the file \fIfilename\fP.
.TP
.B \-d\fInumber\fP
.B \-x \fIcommand\fP
The password is printed by executing the \fIcommand\fP. This is useful
when the password can be safely retrieved from a password manager (like 1Password).
.TP
.B \-d \fInumber\fP
\fInumber\fP is a file descriptor inherited by sshpass from the runner. The
password is read from the open file descriptor.
.TP
.B \-e
The password is taken from the environment variable "SSHPASS".
.TP
.B \-P
.B \-P \fIprompt\fP
Set the password prompt. Sshpass searched for this prompt in the program's
output to the TTY as an indication when to send the password. By default
sshpass looks for the string "assword:" (which matches both "Password:" and
"password:"). If your client's prompt does not fall under either of these,
you can override the default with this option.
.TP
.B \-o \fIotp\fP
\fIotp\fP is the One Time Password coming from a OTP code generator.
.TP
.B \-c \fIcommand\fP
The OTP (One Time Password) is printed by executing the \fIcommand\fP. This is useful
when the OTP can be safely retrieved from a password manager (like 1Password).
.TP
.B \-O \fIprompt\fP
Set the OTP prompt. Sshpass searched for this prompt in the program's
output to the TTY as an indication when to send the OTP code. By default
sshpass looks for the string "Verification code:". If your client's prompt does
not fall under either of these, you can override the default with this option.
.TP
.B \-v
Be verbose. sshpass will output to stderr information that should help debug
cases where the connection hangs, seemingly for no good reason.
Expand Down