I had wanted to have the capability of forcing users to match their username with their cert common name. It's possible to do this using the environment variables passed to an auth script, but I figured it would be useful to add the capability to the auth_pam plugin. It would be nice to be able to pass arbitrary strings from envp to pam so that you could, for instance, use an OU to hold a domain or realm name or some such, but for now I'm just passing the common_name and using it to replace "COMMONNAME", much as the USERNAME and PASSWORD strings get replaced in the pam auth dialog. Here's the patch for the 2.1.3i source I pulled from svn (apologies if this format isn't as it should be, I seldom submit code anywhere):
Index: openvpn/plugin/auth-pam/README =================================================================== --- openvpn/plugin/auth-pam/README (revision 7003) +++ openvpn/plugin/auth-pam/README (working copy) @@ -48,7 +48,7 @@ plugin openvpn-auth-pam.so "test name USERNAME password PASSWORD" -While "USERNAME" and "PASSWORD" are special strings which substitute +While "USERNAME" "COMMONNAME" and "PASSWORD" are special strings which substitute to client-supplied values, it is also possible to name literal values to use as PAM module query responses. For example, suppose that the login module queried for a third parameter, "domain" which Index: openvpn/plugin/auth-pam/auth-pam.c =================================================================== --- openvpn/plugin/auth-pam/auth-pam.c (revision 7003) +++ openvpn/plugin/auth-pam/auth-pam.c (working copy) @@ -81,6 +81,7 @@ * * "USERNAME" -- substitute client-supplied username * "PASSWORD" -- substitute client-specified password + * "COMMONNAME" -- substitute client certificate common name */ #define N_NAME_VALUE 16 @@ -104,6 +105,7 @@ char username[128]; char password[128]; + char common_name[128]; const struct name_value_list *name_value_list; }; @@ -441,12 +443,14 @@ /* get username/password from envp string array */ const char *username = get_env ("username", envp); const char *password = get_env ("password", envp); + const char *common_name = get_env ("common_name", envp) ? get_env ("common_name", envp) : ""; if (username && strlen (username) > 0 && password) { if (send_control (context->foreground_fd, COMMAND_VERIFY) == -1 || send_string (context->foreground_fd, username) == -1 - || send_string (context->foreground_fd, password) == -1) + || send_string (context->foreground_fd, password) == -1 + || send_string (context->foreground_fd, common_name) == -1) { fprintf (stderr, "AUTH-PAM: Error sending auth info to background process\n"); } @@ -563,6 +567,8 @@ return_value = up->username; else if (!strcmp (match_value, "PASSWORD")) return_value = up->password; + else if (!strcmp (match_value, "COMMONNAME")) + return_value = up->common_name; else return_value = match_value; @@ -709,7 +715,8 @@ { case COMMAND_VERIFY: if (recv_string (fd, up.username, sizeof (up.username)) == -1 - || recv_string (fd, up.password, sizeof (up.password)) == -1) + || recv_string (fd, up.password, sizeof (up.password)) == -1 + || recv_string (fd, up.common_name, sizeof (up.common_name)) == -1) { fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n", command);