[RFC PATCH 2/4] pam-ssh-agent: Add reading of one auth key from file

Domenico Andreoli cavokz at gmail.com
Tue Jul 21 11:06:15 AEST 2020


The module needs to read authorized ssh keys from file. Tests validate
the file name and content.

This first implementation reads only one key, support for multiple keys
would be added later.

Fancy ways to obtain auth keys need to be implemented in separate
modules and keys would be shared via PAM environment (to be implemented).

Signed-off-by: Domenico Andreoli <domenico.andreoli at linux.com>

---
 pam-ssh-agent.c          |   64 +++++++++++++++++++++++++++++++++++++++++++++++
 regress/pam-ssh-agent.sh |   24 +++++++++++++++---
 2 files changed, 84 insertions(+), 4 deletions(-)

Index: b/pam-ssh-agent.c
===================================================================
--- a/pam-ssh-agent.c
+++ b/pam-ssh-agent.c
@@ -35,7 +35,12 @@
 #include <pam/pam_modules.h>
 #endif
 
+#include "authfile.h"
+#include "authfd.h"
+#include "ssherr.h"
+
 static int pam_debug;
+static const char *auth_file;
 
 static int
 parse_args(int argc, const char **argv)
@@ -45,6 +50,14 @@ parse_args(int argc, const char **argv)
 	for (i=0; i!=argc; i++) {
 		if (!strcmp(argv[i], "debug")) {
 			pam_debug = 1;
+		} else if (!strncmp(argv[i], "file=", 5)) {
+			if (argv[i][5] == '\0')
+				continue;
+			auth_file = argv[i] + 5;
+			if (auth_file[0] != '/') {
+				syslog(LOG_ERR, "auth file error: Path is not absolute: %s", auth_file);
+				invalid++;
+			}
 		} else {
 			syslog(LOG_ERR, "invalid argument: %s", argv[i]);
 			invalid++;
@@ -54,9 +67,37 @@ parse_args(int argc, const char **argv)
 	return invalid;
 }
 
+static int
+ssh_read_identitylist(const char *filename, struct ssh_identitylist **idlp)
+{
+	struct ssh_identitylist *idl = NULL;
+	int r;
+
+	if ((idl = calloc(1, sizeof(*idl))) == NULL ||
+	    (idl->keys = calloc(1, sizeof(*idl->keys))) == NULL ||
+	    (idl->comments = calloc(1, sizeof(*idl->comments))) == NULL) {
+		r = SSH_ERR_ALLOC_FAIL;
+		goto out;
+	}
+
+	r = sshkey_load_public(filename, &idl->keys[0], &idl->comments[0]);
+	if (r)
+		goto out;
+
+	idl->nkeys = 1;
+	*idlp = idl;
+	idl = NULL;
+
+out:
+	if (idl != NULL)
+		ssh_free_identitylist(idl);
+	return r;
+}
+
 int
 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
 {
+	struct ssh_identitylist *auth_ids = NULL;
 	int ret;
 
 	openlog("pam_ssh_agent_auth", 0, LOG_AUTHPRIV);
@@ -70,11 +111,34 @@ pam_sm_authenticate(pam_handle_t *pamh,
 		const char *user = "(unknown)";
 		pam_get_user(pamh, &user, NULL);
 		syslog(LOG_DEBUG, "USER: %s", user);
+		syslog(LOG_DEBUG, "FILE: %s", auth_file ? auth_file : "(null)");
+	}
+
+	if (auth_file == NULL) {
+		syslog(LOG_ERR, "auth file error: file= is not specified");
+		ret = PAM_SERVICE_ERR;
+		goto out;
+	}
+
+	ret = ssh_read_identitylist(auth_file, &auth_ids);
+	if (ret) {
+		syslog(LOG_ERR, "auth file error: %s: %s", ssh_err(ret), auth_file);
+		ret = PAM_AUTHINFO_UNAVAIL;
+		goto out;
+	}
+
+	if (pam_debug) {
+		unsigned i;
+		syslog(LOG_DEBUG, "auth file has %u key(s):", (unsigned) auth_ids->nkeys);
+		for (i=0; i!=auth_ids->nkeys; i++)
+			syslog(LOG_DEBUG, "  %d) %s", i, auth_ids->comments[i]);
 	}
 
 	ret = PAM_SUCCESS;
 
 out:
+	if (auth_ids != NULL)
+		ssh_free_identitylist(auth_ids);
 	if (pam_debug)
 		syslog(LOG_DEBUG, "result: %s", pam_strerror(pamh, ret));
 	closelog();
Index: b/regress/pam-ssh-agent.sh
===================================================================
--- a/regress/pam-ssh-agent.sh
+++ b/regress/pam-ssh-agent.sh
@@ -14,9 +14,13 @@ export PAM_WRAPPER_SERVICE_DIR=$OBJ/pam-
 
 PAM_SUCCESS=0
 PAM_SERVICE_ERR=3
+PAM_AUTHINFO_UNAVAIL=9
 
 . $OBJ/keytype_gen.sh
 
+first_kt=`echo $ktypes | cut -d" " -f1`
+AUTH_FILE=$OBJ/key.$first_kt.pub
+
 pam_agent_test()
 {
 	rm -rf $PAM_WRAPPER_SERVICE_DIR
@@ -36,8 +40,20 @@ EOF
 trace "invalid arguments"
 expect=$PAM_SERVICE_ERR       pam_agent_test invalid arguments
 
-trace "debug argument"
-expect=$PAM_SUCCESS           pam_agent_test debug
-
 trace "without arguments"
-expect=$PAM_SUCCESS           pam_agent_test
+expect=$PAM_SERVICE_ERR       pam_agent_test # file= is required
+
+trace "with non-absolute auth file path"
+expect=$PAM_SERVICE_ERR       pam_agent_test file=nonabsolute.$$
+
+trace "with non-existent auth file"
+expect=$PAM_AUTHINFO_UNAVAIL  pam_agent_test file=/nonexistent.$$
+
+trace "with empty auth file"
+expect=$PAM_AUTHINFO_UNAVAIL  pam_agent_test file=/dev/null
+
+trace "authenticate agent (debug)"
+expect=$PAM_SUCCESS           pam_agent_test file=$AUTH_FILE debug
+
+trace "authenticate agent (non-debug)"
+expect=$PAM_SUCCESS           pam_agent_test file=$AUTH_FILE



More information about the openssh-unix-dev mailing list