6fbf66fa |
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
* |
49979459 |
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> |
7369d01b |
* Copyright (C) 2016-2018 Selva Nair <selva.nair@gmail.com> |
6fbf66fa |
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* |
caa54ac3 |
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
6fbf66fa |
*/
/*
* OpenVPN plugin module to do PAM authentication using a split
* privilege model.
*/ |
ce8271f5 |
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif |
6fbf66fa |
#include <security/pam_appl.h> |
ce8271f5 |
#ifdef USE_PAM_DLOPEN
#include "pamdl.h" |
6fbf66fa |
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <syslog.h> |
4507bb6c |
#include "utils.h" |
6fbf66fa |
|
ce8271f5 |
#include <openvpn-plugin.h> |
6fbf66fa |
|
e1791bb1 |
#define DEBUG(verb) ((verb) >= 4) |
6fbf66fa |
/* Command codes for foreground -> background communication */
#define COMMAND_VERIFY 0
#define COMMAND_EXIT 1
/* Response codes for background -> foreground communication */
#define RESPONSE_INIT_SUCCEEDED 10
#define RESPONSE_INIT_FAILED 11
#define RESPONSE_VERIFY_SUCCEEDED 12
#define RESPONSE_VERIFY_FAILED 13
|
f403b9a2 |
/* Pointers to functions exported from openvpn */
static plugin_secure_memzero_t plugin_secure_memzero = NULL; |
7369d01b |
static plugin_base64_decode_t plugin_base64_decode = NULL; |
f403b9a2 |
|
6fbf66fa |
/*
* Plugin state, used by foreground
*/
struct auth_pam_context
{ |
81d882d5 |
/* Foreground's socket to background process */
int foreground_fd; |
6fbf66fa |
|
81d882d5 |
/* Process ID of background process */
pid_t background_pid; |
6fbf66fa |
|
81d882d5 |
/* Verbosity level of OpenVPN */
int verb; |
6fbf66fa |
};
/*
* Name/Value pairs for conversation function.
* Special Values:
*
* "USERNAME" -- substitute client-supplied username
* "PASSWORD" -- substitute client-specified password |
6cfada26 |
* "COMMONNAME" -- substitute client certificate common name |
7369d01b |
* "OTP" -- substitute static challenge response if available |
6fbf66fa |
*/
#define N_NAME_VALUE 16
struct name_value { |
81d882d5 |
const char *name;
const char *value; |
6fbf66fa |
};
struct name_value_list { |
81d882d5 |
int len;
struct name_value data[N_NAME_VALUE]; |
6fbf66fa |
};
/*
* Used to pass the username/password
* to the PAM conversation function.
*/
struct user_pass { |
81d882d5 |
int verb; |
6fbf66fa |
|
81d882d5 |
char username[128];
char password[128];
char common_name[128]; |
7369d01b |
char response[128]; |
6fbf66fa |
|
81d882d5 |
const struct name_value_list *name_value_list; |
6fbf66fa |
};
/* Background process function */ |
81d882d5 |
static void pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list); |
6fbf66fa |
/*
* Socket read/write functions.
*/
static int |
81d882d5 |
recv_control(int fd) |
6fbf66fa |
{ |
81d882d5 |
unsigned char c;
const ssize_t size = read(fd, &c, sizeof(c));
if (size == sizeof(c)) |
6fbf66fa |
{ |
81d882d5 |
return c;
}
else
{
/*fprintf (stderr, "AUTH-PAM: DEBUG recv_control.read=%d\n", (int)size);*/
return -1; |
6fbf66fa |
}
}
static int |
81d882d5 |
send_control(int fd, int code) |
6fbf66fa |
{ |
81d882d5 |
unsigned char c = (unsigned char) code;
const ssize_t size = write(fd, &c, sizeof(c));
if (size == sizeof(c))
{
return (int) size;
}
else
{
return -1;
} |
6fbf66fa |
}
static int |
81d882d5 |
recv_string(int fd, char *buffer, int len) |
6fbf66fa |
{ |
81d882d5 |
if (len > 0) |
6fbf66fa |
{ |
81d882d5 |
ssize_t size;
memset(buffer, 0, len);
size = read(fd, buffer, len);
buffer[len-1] = 0;
if (size >= 1)
{
return (int)size;
} |
6fbf66fa |
} |
81d882d5 |
return -1; |
6fbf66fa |
}
static int |
81d882d5 |
send_string(int fd, const char *string) |
6fbf66fa |
{ |
81d882d5 |
const int len = strlen(string) + 1;
const ssize_t size = write(fd, string, len);
if (size == len)
{
return (int) size;
}
else
{
return -1;
} |
6fbf66fa |
}
|
e1791bb1 |
#ifdef DO_DAEMONIZE
|
6fbf66fa |
/*
* Daemonize if "daemon" env var is true.
* Preserve stderr across daemonization if
* "daemon_log_redirect" env var is true.
*/
static void |
81d882d5 |
daemonize(const char *envp[]) |
6fbf66fa |
{ |
81d882d5 |
const char *daemon_string = get_env("daemon", envp);
if (daemon_string && daemon_string[0] == '1')
{
const char *log_redirect = get_env("daemon_log_redirect", envp);
int fd = -1;
if (log_redirect && log_redirect[0] == '1')
{
fd = dup(2);
}
if (daemon(0, 0) < 0)
{
fprintf(stderr, "AUTH-PAM: daemonization failed\n");
}
else if (fd >= 3)
{
dup2(fd, 2);
close(fd);
} |
6fbf66fa |
}
}
|
81d882d5 |
#endif /* ifdef DO_DAEMONIZE */ |
e1791bb1 |
|
6fbf66fa |
/*
* Close most of parent's fds.
* Keep stdin/stdout/stderr, plus one
* other fd which is presumed to be
* our pipe back to parent.
* Admittedly, a bit of a kludge,
* but posix doesn't give us a kind
* of FD_CLOEXEC which will stop
* fds from crossing a fork().
*/
static void |
81d882d5 |
close_fds_except(int keep) |
6fbf66fa |
{ |
81d882d5 |
int i;
closelog();
for (i = 3; i <= 100; ++i) |
6fbf66fa |
{ |
81d882d5 |
if (i != keep)
{
close(i);
} |
6fbf66fa |
}
}
/*
* Usually we ignore signals, because our parent will
* deal with them.
*/
static void |
81d882d5 |
set_signals(void) |
6fbf66fa |
{ |
81d882d5 |
signal(SIGTERM, SIG_DFL); |
6fbf66fa |
|
81d882d5 |
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
signal(SIGPIPE, SIG_IGN); |
6fbf66fa |
}
/*
* Return 1 if query matches match.
*/
static int |
81d882d5 |
name_value_match(const char *query, const char *match) |
6fbf66fa |
{ |
81d882d5 |
while (!isalnum(*query)) |
6fbf66fa |
{ |
81d882d5 |
if (*query == '\0')
{
return 0;
}
++query; |
6fbf66fa |
} |
81d882d5 |
return strncasecmp(match, query, strlen(match)) == 0; |
6fbf66fa |
}
|
7369d01b |
/*
* Split and decode up->password in the form SCRV1:base64_pass:base64_response
* into pass and response and save in up->password and up->response.
* If the password is not in the expected format, input is not changed.
*/
static void
split_scrv1_password(struct user_pass *up)
{
const int skip = strlen("SCRV1:");
if (strncmp(up->password, "SCRV1:", skip) != 0)
{
return;
}
char *tmp = strdup(up->password);
if (!tmp)
{
fprintf(stderr, "AUTH-PAM: out of memory parsing static challenge password\n");
goto out;
}
char *pass = tmp + skip;
char *resp = strchr(pass, ':');
if (!resp) /* string not in SCRV1:xx:yy format */
{
goto out;
}
*resp++ = '\0';
int n = plugin_base64_decode(pass, up->password, sizeof(up->password)-1);
if (n > 0)
{
up->password[n] = '\0';
n = plugin_base64_decode(resp, up->response, sizeof(up->response)-1);
if (n > 0)
{
up->response[n] = '\0';
if (DEBUG(up->verb))
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: parsed static challenge password\n");
}
goto out;
}
}
/* decode error: reinstate original value of up->password and return */
plugin_secure_memzero(up->password, sizeof(up->password));
plugin_secure_memzero(up->response, sizeof(up->response));
strcpy(up->password, tmp); /* tmp is guaranteed to fit in up->password */
fprintf(stderr, "AUTH-PAM: base64 decode error while parsing static challenge password\n");
out:
if (tmp)
{
plugin_secure_memzero(tmp, strlen(tmp));
free(tmp);
}
}
|
f403b9a2 |
OPENVPN_EXPORT int
openvpn_plugin_open_v3(const int v3structver,
struct openvpn_plugin_args_open_in const *args,
struct openvpn_plugin_args_open_return *ret) |
6fbf66fa |
{ |
81d882d5 |
pid_t pid;
int fd[2];
struct auth_pam_context *context;
struct name_value_list name_value_list; |
6fbf66fa |
|
81d882d5 |
const int base_parms = 2;
|
f403b9a2 |
const char **argv = args->argv;
const char **envp = args->envp;
/* Check API compatibility -- struct version 4 or higher needed */
if (v3structver < 4)
{
fprintf(stderr, "AUTH-PAM: This plugin is incompatible with the running version of OpenVPN\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
|
81d882d5 |
/*
* Allocate our context
*/
context = (struct auth_pam_context *) calloc(1, sizeof(struct auth_pam_context));
if (!context) |
6fbf66fa |
{ |
81d882d5 |
goto error; |
6fbf66fa |
} |
81d882d5 |
context->foreground_fd = -1;
/*
* Intercept the --auth-user-pass-verify callback.
*/ |
f403b9a2 |
ret->type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);
/* Save global pointers to functions exported from openvpn */
plugin_secure_memzero = args->callbacks->plugin_secure_memzero; |
7369d01b |
plugin_base64_decode = args->callbacks->plugin_base64_decode; |
81d882d5 |
/*
* Make sure we have two string arguments: the first is the .so name,
* the second is the PAM service type.
*/
if (string_array_len(argv) < base_parms) |
6fbf66fa |
{ |
81d882d5 |
fprintf(stderr, "AUTH-PAM: need PAM service parameter\n");
goto error; |
6fbf66fa |
}
|
81d882d5 |
/*
* See if we have optional name/value pairs to match against
* PAM module queried fields in the conversation function.
*/
name_value_list.len = 0;
if (string_array_len(argv) > base_parms) |
6fbf66fa |
{ |
81d882d5 |
const int nv_len = string_array_len(argv) - base_parms;
int i;
if ((nv_len & 1) == 1 || (nv_len / 2) > N_NAME_VALUE)
{
fprintf(stderr, "AUTH-PAM: bad name/value list length\n");
goto error;
}
name_value_list.len = nv_len / 2;
for (i = 0; i < name_value_list.len; ++i)
{
const int base = base_parms + i * 2;
name_value_list.data[i].name = argv[base];
name_value_list.data[i].value = argv[base+1];
} |
6fbf66fa |
}
|
81d882d5 |
/*
* Get verbosity level from environment
*/ |
6fbf66fa |
{ |
81d882d5 |
const char *verb_string = get_env("verb", envp);
if (verb_string)
{
context->verb = atoi(verb_string);
}
} |
6fbf66fa |
|
81d882d5 |
/*
* Make a socket for foreground and background processes
* to communicate.
*/
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
{
fprintf(stderr, "AUTH-PAM: socketpair call failed\n");
goto error;
} |
6fbf66fa |
|
81d882d5 |
/*
* Fork off the privileged process. It will remain privileged
* even after the foreground process drops its privileges.
*/
pid = fork(); |
6fbf66fa |
|
81d882d5 |
if (pid)
{
int status;
/*
* Foreground Process
*/
context->background_pid = pid;
/* close our copy of child's socket */
close(fd[1]);
/* don't let future subprocesses inherit child socket */
if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0)
{
fprintf(stderr, "AUTH-PAM: Set FD_CLOEXEC flag on socket file descriptor failed\n");
}
/* wait for background child process to initialize */
status = recv_control(fd[0]);
if (status == RESPONSE_INIT_SUCCEEDED)
{
context->foreground_fd = fd[0]; |
f403b9a2 |
ret->handle = (openvpn_plugin_handle_t *) context;
return OPENVPN_PLUGIN_FUNC_SUCCESS; |
81d882d5 |
} |
6fbf66fa |
} |
81d882d5 |
else |
6fbf66fa |
{ |
81d882d5 |
/*
* Background Process
*/ |
6fbf66fa |
|
81d882d5 |
/* close all parent fds except our socket back to parent */
close_fds_except(fd[1]); |
6fbf66fa |
|
81d882d5 |
/* Ignore most signals (the parent will receive them) */
set_signals(); |
6fbf66fa |
|
e1791bb1 |
#ifdef DO_DAEMONIZE |
81d882d5 |
/* Daemonize if --daemon option is set. */
daemonize(envp); |
e1791bb1 |
#endif |
6fbf66fa |
|
81d882d5 |
/* execute the event loop */
pam_server(fd[1], argv[1], context->verb, &name_value_list); |
6fbf66fa |
|
81d882d5 |
close(fd[1]); |
6fbf66fa |
|
81d882d5 |
exit(0);
return 0; /* NOTREACHED */ |
6fbf66fa |
}
|
81d882d5 |
error:
if (context)
{
free(context);
} |
f403b9a2 |
return OPENVPN_PLUGIN_FUNC_ERROR; |
6fbf66fa |
}
OPENVPN_EXPORT int |
81d882d5 |
openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) |
6fbf66fa |
{ |
81d882d5 |
struct auth_pam_context *context = (struct auth_pam_context *) handle;
if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && context->foreground_fd >= 0)
{
/* 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, common_name) == -1)
{
fprintf(stderr, "AUTH-PAM: Error sending auth info to background process\n");
}
else
{
const int status = recv_control(context->foreground_fd);
if (status == RESPONSE_VERIFY_SUCCEEDED)
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
if (status == -1)
{
fprintf(stderr, "AUTH-PAM: Error receiving auth confirmation from background process\n");
}
}
}
}
return OPENVPN_PLUGIN_FUNC_ERROR; |
6fbf66fa |
}
OPENVPN_EXPORT void |
81d882d5 |
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) |
6fbf66fa |
{ |
81d882d5 |
struct auth_pam_context *context = (struct auth_pam_context *) handle; |
6fbf66fa |
|
81d882d5 |
if (DEBUG(context->verb)) |
6fbf66fa |
{ |
81d882d5 |
fprintf(stderr, "AUTH-PAM: close\n");
} |
6fbf66fa |
|
81d882d5 |
if (context->foreground_fd >= 0)
{
/* tell background process to exit */
if (send_control(context->foreground_fd, COMMAND_EXIT) == -1)
{
fprintf(stderr, "AUTH-PAM: Error signaling background process to exit\n");
}
/* wait for background process to exit */
if (context->background_pid > 0)
{
waitpid(context->background_pid, NULL, 0);
}
close(context->foreground_fd);
context->foreground_fd = -1; |
6fbf66fa |
}
|
81d882d5 |
free(context); |
6fbf66fa |
}
OPENVPN_EXPORT void |
81d882d5 |
openvpn_plugin_abort_v1(openvpn_plugin_handle_t handle) |
6fbf66fa |
{ |
81d882d5 |
struct auth_pam_context *context = (struct auth_pam_context *) handle; |
6fbf66fa |
|
81d882d5 |
/* tell background process to exit */
if (context && context->foreground_fd >= 0) |
6fbf66fa |
{ |
81d882d5 |
send_control(context->foreground_fd, COMMAND_EXIT);
close(context->foreground_fd);
context->foreground_fd = -1; |
6fbf66fa |
}
}
/*
* PAM conversation function
*/
static int |
81d882d5 |
my_conv(int n, const struct pam_message **msg_array,
struct pam_response **response_array, void *appdata_ptr) |
6fbf66fa |
{ |
81d882d5 |
const struct user_pass *up = ( const struct user_pass *) appdata_ptr;
struct pam_response *aresp;
int i;
int ret = PAM_SUCCESS;
*response_array = NULL;
if (n <= 0 || n > PAM_MAX_NUM_MSG)
{
return (PAM_CONV_ERR);
}
if ((aresp = calloc(n, sizeof *aresp)) == NULL)
{
return (PAM_BUF_ERR);
}
/* loop through each PAM-module query */
for (i = 0; i < n; ++i)
{
const struct pam_message *msg = msg_array[i];
aresp[i].resp_retcode = 0;
aresp[i].resp = NULL;
if (DEBUG(up->verb))
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: my_conv[%d] query='%s' style=%d\n",
i,
msg->msg ? msg->msg : "NULL",
msg->msg_style);
}
if (up->name_value_list && up->name_value_list->len > 0)
{
/* use name/value list match method */
const struct name_value_list *list = up->name_value_list;
int j;
/* loop through name/value pairs */
for (j = 0; j < list->len; ++j)
{
const char *match_name = list->data[j].name;
const char *match_value = list->data[j].value;
if (name_value_match(msg->msg, match_name))
{
/* found name/value match */
aresp[i].resp = NULL;
if (DEBUG(up->verb))
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: name match found, query/match-string ['%s', '%s'] = '%s'\n",
msg->msg,
match_name,
match_value);
}
if (strstr(match_value, "USERNAME"))
{
aresp[i].resp = searchandreplace(match_value, "USERNAME", up->username);
}
else if (strstr(match_value, "PASSWORD"))
{
aresp[i].resp = searchandreplace(match_value, "PASSWORD", up->password);
}
else if (strstr(match_value, "COMMONNAME"))
{
aresp[i].resp = searchandreplace(match_value, "COMMONNAME", up->common_name);
} |
7369d01b |
else if (strstr(match_value, "OTP"))
{
aresp[i].resp = searchandreplace(match_value, "OTP", up->response);
} |
81d882d5 |
else
{
aresp[i].resp = strdup(match_value);
}
if (aresp[i].resp == NULL)
{
ret = PAM_CONV_ERR;
}
break;
}
}
if (j == list->len)
{
ret = PAM_CONV_ERR;
}
}
else
{
/* use PAM_PROMPT_ECHO_x hints */
switch (msg->msg_style)
{
case PAM_PROMPT_ECHO_OFF:
aresp[i].resp = strdup(up->password);
if (aresp[i].resp == NULL)
{
ret = PAM_CONV_ERR;
}
break;
case PAM_PROMPT_ECHO_ON:
aresp[i].resp = strdup(up->username);
if (aresp[i].resp == NULL)
{
ret = PAM_CONV_ERR;
}
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
break;
default:
ret = PAM_CONV_ERR;
break;
}
}
}
if (ret == PAM_SUCCESS)
{
*response_array = aresp;
}
else
{
free(aresp);
}
return ret; |
6fbf66fa |
}
/*
* Return 1 if authenticated and 0 if failed.
* Called once for every username/password
* to be authenticated.
*/
static int |
81d882d5 |
pam_auth(const char *service, const struct user_pass *up) |
6fbf66fa |
{ |
81d882d5 |
struct pam_conv conv;
pam_handle_t *pamh = NULL;
int status = PAM_SUCCESS;
int ret = 0;
const int name_value_list_provided = (up->name_value_list && up->name_value_list->len > 0);
/* Initialize PAM */
conv.conv = my_conv;
conv.appdata_ptr = (void *)up;
status = pam_start(service, name_value_list_provided ? NULL : up->username, &conv, &pamh);
if (status == PAM_SUCCESS)
{
/* Call PAM to verify username/password */
status = pam_authenticate(pamh, 0);
if (status == PAM_SUCCESS)
{
status = pam_acct_mgmt(pamh, 0);
}
if (status == PAM_SUCCESS)
{
ret = 1;
}
/* Output error message if failed */
if (!ret)
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: user '%s' failed to authenticate: %s\n",
up->username,
pam_strerror(pamh, status));
}
/* Close PAM */
pam_end(pamh, status);
}
return ret; |
6fbf66fa |
}
/*
* Background process -- runs with privilege.
*/
static void |
81d882d5 |
pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list) |
6fbf66fa |
{ |
81d882d5 |
struct user_pass up;
int command; |
ce8271f5 |
#ifdef USE_PAM_DLOPEN |
81d882d5 |
static const char pam_so[] = "libpam.so"; |
6fbf66fa |
#endif
|
81d882d5 |
/*
* Do initialization
*/
if (DEBUG(verb))
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: INIT service='%s'\n", service);
} |
6fbf66fa |
|
ce8271f5 |
#ifdef USE_PAM_DLOPEN |
81d882d5 |
/*
* Load PAM shared object
*/
if (!dlopen_pam(pam_so)) |
6fbf66fa |
{ |
81d882d5 |
fprintf(stderr, "AUTH-PAM: BACKGROUND: could not load PAM lib %s: %s\n", pam_so, dlerror());
send_control(fd, RESPONSE_INIT_FAILED);
goto done; |
6fbf66fa |
}
#endif
|
81d882d5 |
/*
* Tell foreground that we initialized successfully
*/
if (send_control(fd, RESPONSE_INIT_SUCCEEDED) == -1) |
6fbf66fa |
{ |
81d882d5 |
fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [1]\n");
goto done; |
6fbf66fa |
}
|
81d882d5 |
/*
* Event loop
*/
while (1) |
6fbf66fa |
{ |
81d882d5 |
memset(&up, 0, sizeof(up));
up.verb = verb;
up.name_value_list = name_value_list;
/* get a command from foreground process */
command = recv_control(fd);
if (DEBUG(verb))
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: received command code: %d\n", command);
}
switch (command)
{
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.common_name, sizeof(up.common_name)) == -1)
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n",
command);
goto done;
}
if (DEBUG(verb))
{ |
1e0b7141 |
#if 0 |
81d882d5 |
fprintf(stderr, "AUTH-PAM: BACKGROUND: USER/PASS: %s/%s\n",
up.username, up.password); |
1e0b7141 |
#else |
81d882d5 |
fprintf(stderr, "AUTH-PAM: BACKGROUND: USER: %s\n", up.username); |
1e0b7141 |
#endif |
81d882d5 |
}
|
7369d01b |
/* If password is of the form SCRV1:base64:base64 split it up */
split_scrv1_password(&up);
|
81d882d5 |
if (pam_auth(service, &up)) /* Succeeded */
{
if (send_control(fd, RESPONSE_VERIFY_SUCCEEDED) == -1)
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [2]\n");
goto done;
}
}
else /* Failed */
{
if (send_control(fd, RESPONSE_VERIFY_FAILED) == -1)
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [3]\n");
goto done;
}
} |
f403b9a2 |
plugin_secure_memzero(up.password, sizeof(up.password)); |
81d882d5 |
break;
case COMMAND_EXIT:
goto done;
case -1:
fprintf(stderr, "AUTH-PAM: BACKGROUND: read error on command channel\n");
goto done;
default:
fprintf(stderr, "AUTH-PAM: BACKGROUND: unknown command code: code=%d, exiting\n",
command);
goto done;
} |
7369d01b |
plugin_secure_memzero(up.response, sizeof(up.response)); |
81d882d5 |
}
done: |
f403b9a2 |
plugin_secure_memzero(up.password, sizeof(up.password)); |
7369d01b |
plugin_secure_memzero(up.response, sizeof(up.response)); |
ce8271f5 |
#ifdef USE_PAM_DLOPEN |
81d882d5 |
dlclose_pam(); |
6fbf66fa |
#endif |
81d882d5 |
if (DEBUG(verb))
{
fprintf(stderr, "AUTH-PAM: BACKGROUND: EXIT\n");
} |
6fbf66fa |
|
81d882d5 |
return; |
6fbf66fa |
} |