Skip to content

Instantly share code, notes, and snippets.

@leiless
Last active July 1, 2024 03:33
Show Gist options
  • Save leiless/63595ec49d446beac79579af2ef08bf0 to your computer and use it in GitHub Desktop.
Save leiless/63595ec49d446beac79579af2ef08bf0 to your computer and use it in GitHub Desktop.
sshpass main.c diff 1.09 vs 1.10
diff --git a/sshpass-1.09/main.c b/sshpass-1.10/main.c
index 8a75d61..2bad28b 100644
--- a/sshpass-1.09/main.c
+++ b/sshpass-1.10/main.c
@@ -29,6 +29,7 @@
#include <sys/ioctl.h>
#include <sys/select.h>
+#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
@@ -50,6 +51,7 @@ enum program_return_codes {
RETURN_INCORRECT_PASSWORD,
RETURN_HOST_KEY_UNKNOWN,
RETURN_HOST_KEY_CHANGED,
+ RETURN_HELP,
};
// Some systems don't define posix_openpt
@@ -61,12 +63,15 @@ posix_openpt(int flags)
}
#endif
+#define DEFAULT_ENV_PASSWORD "SSHPASS"
+
int runprogram( int argc, char *argv[] );
void reliable_write( int fd, const void *data, size_t size );
int handleoutput( int fd );
void window_resize_handler(int signum);
void sigchld_handler(int signum);
void term_handler(int signum);
+void term_child(int signum);
int match( const char *reference, const char *buffer, ssize_t bufsize, int state );
void write_pass( int fd );
@@ -83,19 +88,34 @@ struct {
char *orig_password;
} args;
+static void hide_password()
+{
+ assert(args.pwsrc.password==NULL);
+
+ args.pwsrc.password = strdup(args.orig_password);
+
+ // Hide the original password from prying eyes
+ while( *args.orig_password != '\0' ) {
+ *args.orig_password = '\0';
+ ++args.orig_password;
+ }
+
+ args.orig_password = NULL;
+}
+
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"
- " -P prompt Which string should sshpass search for to detect a password prompt\n"
- " -v Be verbose about what you're doing\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");
+ printf("Usage: " PACKAGE_NAME " [-f|-d|-p|-e[env_var]] [-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[env_var] Password is passed as env-var \"env_var\" if given, \"SSHPASS\" otherwise.\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"
+ " -v Be verbose about what you're doing.\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
@@ -113,7 +133,7 @@ static int parse_options( int argc, char *argv[] )
fprintf(stderr, "Conflicting password source\n"); \
error=RETURN_CONFLICTING_ARGUMENTS; }
- while( (opt=getopt(argc, argv, "+f:d:p:P:heVv"))!=-1 && error==-1 ) {
+ while( (opt=getopt(argc, argv, "+f:d:p:P:he::Vv"))!=-1 && error==-1 ) {
switch( opt ) {
case 'f':
// Password should come from a file
@@ -146,24 +166,29 @@ static int parse_options( int argc, char *argv[] )
VIRGIN_PWTYPE;
args.pwtype=PWT_PASS;
- args.orig_password=getenv("SSHPASS");
+ if( optarg==NULL )
+ optarg = "SSHPASS";
+ args.orig_password=getenv(optarg);
+
if( args.orig_password==NULL ) {
- fprintf(stderr, "SSHPASS: -e option given but SSHPASS environment variable not set\n");
+ fprintf(stderr, "sshpass: -e option given but \"%s\" environment variable is not set.\n", optarg);
error=RETURN_INVALID_ARGUMENTS;
}
+
+ hide_password();
+ unsetenv(optarg);
break;
case '?':
case ':':
error=RETURN_INVALID_ARGUMENTS;
break;
case 'h':
- error=RETURN_NOERROR;
- break;
+ return -(RETURN_HELP+1);
case 'V':
printf("%s\n"
"(C) 2006-2011 Lingnu Open Source Consulting Ltd.\n"
- "(C) 2015-2016, 2021 Shachar Shemesh\n"
+ "(C) 2015-2016, 2021-2022 Shachar Shemesh\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"
"\n"
@@ -183,9 +208,14 @@ int main( int argc, char *argv[] )
{
int opt_offset=parse_options( argc, argv );
+ if( opt_offset==-(RETURN_HELP+1) ) {
+ show_help();
+ return 0;
+ }
+
if( opt_offset<0 ) {
// There was some error
- show_help();
+ fprintf(stderr, "Use \"sshpass -h\" to get help\n");
return -(opt_offset+1); // -1 becomes 0, -2 becomes 1 etc.
}
@@ -197,13 +227,7 @@ int main( int argc, char *argv[] )
}
if( args.orig_password!=NULL ) {
- args.pwsrc.password = strdup(args.orig_password);
-
- // Hide the original password from prying eyes
- while( *args.orig_password != '\0' ) {
- *args.orig_password = 'x';
- ++args.orig_password;
- }
+ hide_password();
}
return runprogram( argc-opt_offset, argv+opt_offset );
@@ -214,7 +238,7 @@ static int ourtty; // Our own tty
static int masterpt;
int childpid;
-int term;
+int termsig;
int runprogram( int argc, char *argv[] )
{
@@ -310,18 +334,16 @@ int runprogram( int argc, char *argv[] )
// Detach us from the current TTY
setsid();
- // This line makes the ptty our controlling tty. We do not otherwise need it open
- slavept=open(name, O_RDWR );
-#ifdef TIOCSCTTY
- // On some systems, an open(2) is insufficient to set the
- // controlling tty (see the documentation for TIOCSCTTY in
- // tty(4)).
- if (ioctl(slavept, TIOCSCTTY) == -1) {
+
+ // Attach the process to a controlling TTY.
+ slavept=open(name, O_RDWR | O_NOCTTY);
+ // On some systems, an open(2) is insufficient to set the controlling tty (see the documentation for
+ // TIOCSCTTY in tty(4)).
+ if (ioctl(slavept, TIOCSCTTY, 0) == -1) {
perror("sshpass: Failed to set controlling terminal in child (TIOCSCTTY)");
exit(RETURN_RUNTIME_ERROR);
}
-#endif
- close( slavept );
+ close( slavept ); // We don't need the controlling TTY actually open
close( masterpt );
@@ -362,6 +384,16 @@ int runprogram( int argc, char *argv[] )
int selret=pselect( masterpt+1, &readfd, NULL, NULL, NULL, &sigmask_select );
+ if( termsig!=0 ) {
+ // Copying termsig isn't strictly necessary, as signals are masked at this point.
+ int signum = termsig;
+ termsig = 0;
+
+ term_child(signum);
+
+ continue;
+ }
+
if( selret>0 ) {
if( FD_ISSET( masterpt, &readfd ) ) {
int ret;
@@ -546,6 +578,13 @@ void sigchld_handler(int signum)
}
void term_handler(int signum)
+{
+ // BUG: There is a potential race here if two signals arrive before the main code had a chance to handle them.
+ // This seems low enough risk not to justify the extra code to correctly handle this.
+ termsig = signum;
+}
+
+void term_child(int signum)
{
fflush(stdout);
switch(signum) {
@@ -560,8 +599,6 @@ void term_handler(int signum)
kill( childpid, signum );
}
}
-
- term = 1;
}
void reliable_write( int fd, const void *data, size_t size )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment