[Rpm-maint] [PATCH v9 13/13] Add support for prompting the user for the password using pinentry

Fionnuala Gunter fionnuala.gunter at gmail.com
Tue Jul 21 17:00:47 UTC 2015


From: Mimi Zohar <zohar at us.ibm.com>

Call pinentry to prompt for the password. On failure revert back
to prompting the user directly.
---
 lib/rpmsignfiles.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/rpmsignfiles.h |   1 +
 rpmsign.c          |   4 +-
 3 files changed, 134 insertions(+), 1 deletion(-)

diff --git a/lib/rpmsignfiles.c b/lib/rpmsignfiles.c
index 4336f8c..cd93fc6 100644
--- a/lib/rpmsignfiles.c
+++ b/lib/rpmsignfiles.c
@@ -7,7 +7,10 @@
 #include "system.h"
 #include "imaevm.h"
 
+#include <unistd.h>
 #include <termios.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #include <rpm/rpmlog.h>		/* rpmlog */
 #include <rpm/rpmstring.h>	/* rnibble */
@@ -32,6 +35,23 @@ static const char *hash_algo_name[] = {
     [PGPHASHALGO_SHA224]       = "sha224",
 };
 
+#define debug	0
+
+#define PARENT_WRITE_PIPE  0
+#define PARENT_READ_PIPE   1
+
+#define NUM_PIPES          2
+int pipes[NUM_PIPES][2];
+
+#define READ_FD  0
+#define WRITE_FD 1
+
+#define PARENT_READ_FD  ( pipes[PARENT_READ_PIPE][READ_FD]   )
+#define PARENT_WRITE_FD ( pipes[PARENT_WRITE_PIPE][WRITE_FD] )
+
+#define CHILD_READ_FD   ( pipes[PARENT_WRITE_PIPE][READ_FD]  )
+#define CHILD_WRITE_FD  ( pipes[PARENT_READ_PIPE][WRITE_FD]  )
+
 char *get_fskpass(void)
 {
     struct termios flags, tmp_flags;
@@ -65,6 +85,116 @@ char *get_fskpass(void)
     return pwd;
 }
 
+static void send(int pipe, char *command)
+{
+    if (debug)
+	printf("send: %s", command);
+    write(PARENT_WRITE_FD, command, strlen(command));
+}
+
+static void recv(int pipe)
+{
+    char buffer[100];
+    int count;
+
+    do {
+	count = read(PARENT_READ_FD, buffer, sizeof buffer - 1);
+	if (count <= 0)
+	     break;
+	if (strncmp(buffer, "OK", 2) != 0) {
+	    if (debug)
+		printf("count %d: %s\n", count, buffer);
+		break;
+	} else if (debug)
+	     printf("count %d: %s\n", count, buffer);
+    } while (0);
+}
+
+static char *recv_password(int pipe)
+{
+    long count;
+    size_t buflen = 100;
+    char *buffer = malloc(buflen);
+
+    if (!buffer)
+	return NULL;
+
+    do {
+	memset(buffer, '\0', buflen);
+	count = read(PARENT_READ_FD, buffer, buflen);
+
+	if (count > 0 && buffer[0] == 'D') {
+	    char *password;
+	    int len = strlen(buffer);
+
+	    if (buffer[len - 1] == '\n')
+		buffer[len - 1] = '\0';
+	    password = strdup(buffer + 2);
+	    memset(buffer, '\0', buflen);
+	    return password;
+	} else if (count > 0 && strncmp(buffer, "ERR", 3) == 0)
+	    return NULL;
+	else if (count > 0 && strncmp(buffer, "OK", 2) == 0)
+	    return NULL;
+    } while (0);
+
+    return NULL;
+}
+
+char *get_pinentry_fskpass()
+{
+    char *command, *password = NULL;
+    pid_t child;
+
+    if (pipe(pipes[PARENT_READ_PIPE]) || pipe(pipes[PARENT_WRITE_PIPE])) {
+	fprintf(stderr, "Pipe failed\n");
+	return NULL;
+    }
+
+    child = fork();
+    if (child == (pid_t) 0) {
+	dup2(CHILD_READ_FD, STDIN_FILENO);
+	dup2(CHILD_WRITE_FD, STDOUT_FILENO);
+
+	close(CHILD_READ_FD);
+	close(CHILD_WRITE_FD);
+	close(PARENT_READ_FD);
+	close(PARENT_WRITE_FD);
+
+	execlp("pinentry", "pinentry", NULL);
+    } else if (child < (pid_t) 0) {
+	fprintf(stderr, "Fork failed\n");
+	    return NULL;
+    } else {
+	/* close fds not required by parent */
+	close(CHILD_READ_FD);
+	close(CHILD_WRITE_FD);
+
+	command = "SETDESC PEM password\n";
+	send(PARENT_WRITE_FD, command);
+	recv(PARENT_READ_FD);
+
+	command = "OPTION display PEM\n";
+	send(PARENT_WRITE_FD, command);
+	recv(PARENT_READ_FD);
+
+	command = "OPTION ttyname ttyname(0)\n";
+	send(PARENT_WRITE_FD, command);
+	recv(PARENT_READ_FD);
+
+	command = "GETPIN\n";
+	send(PARENT_WRITE_FD, command);
+	password = recv_password(PARENT_READ_FD);
+
+	command = "BYE\n";
+	send(PARENT_WRITE_FD, command);
+	recv(PARENT_READ_FD);
+
+	waitpid(child, NULL, 0);
+    }
+    return password;
+}
+
 static char *signFile(const char *algo, const char *fdigest, int diglen,
 const char *key, char *keypass)
 {
diff --git a/lib/rpmsignfiles.h b/lib/rpmsignfiles.h
index 52e2482..b00703d 100644
--- a/lib/rpmsignfiles.h
+++ b/lib/rpmsignfiles.h
@@ -15,6 +15,7 @@ extern "C" {
 rpmRC rpmSignFiles(Header h, const char *key, char *keypass);
 
 char *get_fskpass(void); /* get file signing key password */
+char *get_pinentry_fskpass(void); /* call pinentry to get password */
 
 #ifdef _cplusplus
 }
diff --git a/rpmsign.c b/rpmsign.c
index 7f48d98..0cfbc92 100644
--- a/rpmsign.c
+++ b/rpmsign.c
@@ -81,7 +81,9 @@ static int doSign(poptContext optCon)
 #ifndef WITH_IMAEVM
 	    argerror(_("--fskpass may only be specified when signing files"));
 #else
-	    fileSigningKeyPassword = get_fskpass();
+	    fileSigningKeyPassword = get_pinentry_fskpass();
+	    if (!fileSigningKeyPassword)
+		fileSigningKeyPassword = get_fskpass();
 #endif
 	}
 
-- 
2.4.3



More information about the Rpm-maint mailing list