Something went wrong on our end
pam_authclient.c 5.07 KiB
#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include "auth_client.h"
/* These #defines must be present according to PAM documentation. */
#define PAM_SM_AUTH
#ifdef HAVE_SECURITY_PAM_APPL_H
#include <security/pam_appl.h>
#endif
#ifdef HAVE_SECURITY_PAM_MODULES_H
#include <security/pam_modules.h>
#endif
#ifdef HAVE_PAM_PAM_APPL_H
#include <pam/pam_appl.h>
#endif
#ifdef HAVE_PAM_PAM_MODULES_H
#include <pam/pam_modules.h>
#endif
#ifndef PAM_EXTERN
#ifdef PAM_STATIC
#define PAM_EXTERN static
#else
#define PAM_EXTERN extern
#endif
#endif
static const char *kPasswordPrompt = "Password: ";
static const char *kOtpPrompt = "OTP Token: ";
struct cfg {
int debug;
int use_first_pass;
int try_first_pass;
char *auth_server;
char *ssl_crt;
char *ssl_key;
char *ca_file;
};
static void parse_cfg(int argc, const char **argv, struct cfg *cfg) {
int i;
memset(cfg, 0, sizeof(struct cfg));
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "debug")) {
cfg->debug = 1;
} else if (!strcmp(argv[i], "try_first_pass")) {
cfg->try_first_pass = 1;
} else if (!strcmp(argv[i], "use_first_pass")) {
cfg->use_first_pass = 1;
} else if (!strncmp(argv[i], "auth_server=", 12)) {
cfg->auth_server = (char *)(argv[i] + 12);
} else if (!strncmp(argv[i], "ssl_crt=", 8)) {
cfg->ssl_crt = (char *)(argv[i] + 8);
} else if (!strncmp(argv[i], "ssl_key=", 8)) {
cfg->ssl_key = (char *)(argv[i] + 8);
} else if (!strncmp(argv[i], "ca=", 3)) {
cfg->ca_file = (char *)(argv[i] + 3);
}
}
}
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,
int flags, int argc, const char **argv) {
int i, retval, err;
const char *service = NULL;
const char *username = NULL;
const char *password = NULL;
const char *otp_token = NULL;
const char *source_ip = NULL;
struct pam_conv *conv = NULL;
struct cfg cfg;
auth_client_t ac;
parse_cfg(argc, argv, &cfg);
err = pam_get_user(pamh, &username, NULL);
if (err != PAM_SUCCESS) {
D(("pam_get_user() error: %s", pam_strerror(pamh, err)));
return PAM_AUTH_ERR;
}
err = pam_get_item(pamh, PAM_SERVICE, (PAM_CONST void **)&service);
if (err != PAM_SUCCESS) {
D(("pam_get_item(service) error: %s", pam_strerror(pamh, err)));
return PAM_AUTH_ERR;
}
pam_get_item(pamh, PAM_RHOST, (PAM_CONST void **)&source_ip);
if (cfg.try_first_pass || cfg.use_first_pass) {
if (pam_get_item(pamh, PAM_AUTHTOK, (PAM_CONST void **)&password) != PAM_SUCCESS) {
return PAM_AUTH_ERR;
}
}
if (cfg.use_first_pass && password == NULL) {
return PAM_AUTH_ERR;
}
if (password == NULL) {
// Ask for the password interactively.
struct pam_message *pmsg[1], msg[1];
struct pam_response *resp;
err = pam_get_item(pamh, PAM_CONV, (PAM_CONST void **)&conv);
if (err != PAM_SUCCESS) {
D(("pam_get_item(conv) error: %s", pam_strerror(pamh, err)));
return PAM_AUTH_ERR;
}
pmsg[0] = &msg[0];
msg[0].msg = (char *)kPasswordPrompt;
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
err = conv->conv(1, (const struct pam_message **)pmsg,
&resp, conv->appdata_ptr);
if (err != PAM_SUCCESS) {
D(("conv() error: %s", pam_strerror(pamh, err)));
return PAM_AUTH_ERR;
}
password = resp->resp;
}
// Create the auth client request.
ac = auth_client_new(service, cfg.auth_server);
if (cfg.ssl_crt && cfg.ssl_key && cfg.ca_file) {
auth_client_set_certificate(ac, cfg.ca_file, cfg.ssl_crt, cfg.ssl_key);
}
retval = PAM_AUTH_ERR;
// Allow two authentication attempts in case we receive an
// OTP_REQUIRED response from the server.
for (i = 0; i < 2; i++) {
int ac_err = auth_client_authenticate(ac, username, password, otp_token, source_ip);
if (ac_err == AC_OK) {
retval = PAM_SUCCESS;
} else if (ac_err == AC_ERR_OTP_REQUIRED) {
struct pam_message *pmsg[1], msg[1];
struct pam_response *resp;
// Ask for the OTP token interactively.
if (conv == NULL) {
err = pam_get_item(pamh, PAM_CONV, (PAM_CONST void **)&conv);
if (err != PAM_SUCCESS) {
D(("pam_get_item(conv) error: %s", pam_strerror(pamh, err)));
break;
}
}
pmsg[0] = &msg[0];
msg[0].msg = (char *)kOtpPrompt;
msg[0].msg_style = PAM_PROMPT_ECHO_ON;
err = conv->conv(1, (const struct pam_message **)pmsg,
&resp, conv->appdata_ptr);
if (err != PAM_SUCCESS) {
D(("conv() error: %s", pam_strerror(pamh, err)));
break;
}
otp_token = resp->resp;
continue;
} else {
D(("auth_client error: %s", auth_client_strerror(ac_err)));
}
break;
}
auth_client_free(ac);
return retval;
}
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pam, int flags, int argc, const char **argv) {
return PAM_SUCCESS;
}
#ifdef PAM_STATIC
struct pam_module _pam_authclient_modstruct = {
"pam_authclient",
pam_sm_authenticate,
pam_sm_setcred,
NULL,
NULL,
NULL,
NULL
};
#endif