[Swan] SUCCESS Re: NEW PROBLEM Re: IKEv2 PAM auth failure - how it's done properly?

Paul Wouters paul at nohats.ca
Tue Jan 25 05:24:06 EET 2022


On Mon, 24 Jan 2022, Mirsad Goran Todorovac wrote:

> I can publish a patch diff. I have really made very small modifications. A couple of lines.

> I would also want to map certificate subject lines to unix usernames, put the user into utmp and display the connected user with `w`
> or `who` commands. But I'm not sure how it's done yet.

Attached is what I had gobbled together to pull IDs from certificates inside pam_url for IKEv2.

> Maybe I should think of forking pam_url and supplying a Debian .deb package, since only .rpm exists in the wild?

I don't think it is well maintained or active upstream?

> pam-authenticate is a very practical method of access control. I would like to clear the doubts that it decreased the security of
> IKEv2 VPN, and that it is unprofessional, because pam_url calls a cgi-bin script in .php over a TLSv1.3 connection.

It still beats 10 round trips of EAPTLS on Windows :)

Paul
-------------- next part --------------
diff -Naur pam_url-0.3.3-orig/examples/pam_url.conf pam_url-0.3.3/examples/pam_url.conf
--- pam_url-0.3.3-orig/examples/pam_url.conf	2013-11-18 17:04:54.000000000 -0500
+++ pam_url-0.3.3/examples/pam_url.conf	2017-09-23 13:07:07.760000000 -0400
@@ -6,10 +6,10 @@
     {
         url         = "https://totp.example.com/"; # URI to fetch
         returncode  = "OK";                        # The remote script/cgi should return a 200 http code and this string as its only results
-        userfield   = "user";                      # userfield name to send
-        passwdfield = "token";                     # passwdfield name to send
-        extradata   = "&do=login";                 # extra data to send
-        prompt      = "Token: ";                   # password prompt
+        userfield   = "username";                  # userfield name to send
+        passwdfield = "password";                  # passwdfield name to send
+        extradata   = "&clientIP";                 # extra data to send
+        prompt      = "password: ";                   # password prompt
     };
 
     ssl:
diff -Naur pam_url-0.3.3-orig/pam_url.c pam_url-0.3.3/pam_url.c
--- pam_url-0.3.3-orig/pam_url.c	2013-11-18 17:04:54.000000000 -0500
+++ pam_url-0.3.3/pam_url.c	2017-09-23 13:16:40.141000000 -0400
@@ -18,7 +18,6 @@
 {
 	char* p = NULL;
 	const char *prompt;
-	int prompt_len = 0;
 
 	if(config_lookup_string(&config, "pam_url.settings.prompt", &prompt) == CONFIG_FALSE)
 		prompt = DEF_PROMPT;
@@ -199,7 +198,23 @@
 	if( NULL == (eh = curl_easy_init() ) )
 		goto curl_error;
 
-	char *safe_user = curl_easy_escape(eh, opts.user, 0);
+	/* 512 matches libreswan's IDTOA_BUF */
+	char *user_start;
+	char *user_end;
+	char *username = malloc(512);
+	strncpy(username, opts.user, 512);
+	user_start = strstr(username, "CN=");
+	if(user_start != NULL) {
+		user_start = user_start + sizeof("CN=") - 1;
+		user_end = strstr(user_start, "@");
+		if(user_end != NULL)
+			user_end[0] = '\0';
+		else
+			user_start = username;
+	} else
+		user_start = username;
+
+	char *safe_user = curl_easy_escape(eh, user_start, 0);
 	if( safe_user == NULL )
 		goto curl_error;
 	
@@ -228,15 +243,19 @@
 	if( safe_passwd == NULL )
 		goto curl_error;
 
-	ret = asprintf(&post, "%s=%s&%s=%s&mode=%s%s", opts.user_field,
+	const char *clientIP;
+	if (PAM_SUCCESS != pam_get_item(pamh, PAM_RHOST, (const void **)&clientIP))
+		debug(pamh, "Could not get PAM_RHOST from pam.");
+	else
+		debug(pamh, "PAM_RHOST retrieved from pam.");
+
+	ret = asprintf(&post, "%s=%s&%s=%s%s%s", opts.user_field,
 							safe_user,
 							opts.passwd_field,
 							safe_passwd,
-							opts.mode,
-							opts.extra_field);
-	
-	curl_free(safe_passwd);
-	curl_free(safe_user);
+							/* opts.mode, */
+							opts.extra_field,
+							clientIP);
 
 	if (ret == -1)
 		// If this happens, the contents of post are undefined, we could
@@ -255,9 +274,10 @@
 		if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_DEBUGFUNCTION, curl_debug) )
 			goto curl_error;
 	}
-
+/*
 	if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_POSTFIELDS, post) )
 		goto curl_error;
+*/
 
 	if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_USERAGENT, USER_AGENT) )
 		goto curl_error;
@@ -265,7 +285,16 @@
 	if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, curl_wf) )
 		goto curl_error;
 
-	if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_URL, opts.url) )
+	char *newurl, *baseurl;
+	baseurl = malloc(strlen(opts.url));
+	strncpy(baseurl, opts.url, strlen(opts.url));
+	/* baseurl[strlen(opts.url)-1] = '\0'; */
+	ret = asprintf(&newurl,"%s?%s",opts.url, post); 
+	free(baseurl);
+	if (ret == -1)
+		goto curl_error;
+
+	if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_URL, newurl) )
 		goto curl_error;
 
 	if( CURLE_OK != curl_easy_setopt(eh, CURLOPT_SSLCERT, opts.ssl_cert) )
@@ -312,11 +341,20 @@
 		goto curl_error;
 
 	// No errors
+	free(username);
+	curl_free(safe_user);
+	curl_free(safe_passwd);
 	curl_easy_cleanup(eh);
 	free(post);
 	return PAM_SUCCESS;
 
 curl_error:
+	if(username != NULL)
+		free(username);
+	if(safe_user != NULL)
+		curl_free(safe_user);
+	if(safe_passwd != NULL)
+		curl_free(safe_passwd);
 	if (eh != NULL)
 		curl_easy_cleanup(eh);
 	if (post != NULL)
@@ -333,8 +371,7 @@
 		return PAM_AUTH_ERR;
 	}
 
-	if( strlen(opts.ret_code) == recvbuf_size &&
-            0 == strncmp(opts.ret_code, recvbuf, recvbuf_size) )
+	if (strstr(recvbuf, opts.ret_code) != NULL)
 	{
 		return PAM_SUCCESS;
 	}


More information about the Swan mailing list