335 lines
9.7 KiB
C
335 lines
9.7 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2001, 2002
|
|
* Antti Tapaninen <aet@cc.hut.fi>
|
|
* Anna Erika Suortti <asuortti@cc.hut.fi>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#include "pam_support.h"
|
|
#include "scam.h"
|
|
|
|
#define PAM_SM_AUTH
|
|
#define PAM_SM_ACCOUNT
|
|
#define PAM_SM_SESSION
|
|
#define PAM_SM_PASSWORD
|
|
|
|
static scam_context sctx = {0,};
|
|
|
|
typedef struct _scam_msg_data {
|
|
pam_handle_t *pamh;
|
|
unsigned int *ctrl;
|
|
} scam_msg_data;
|
|
|
|
static void printmsg(scam_context * sctx, char *str)
|
|
{
|
|
scam_msg_data *msg = (scam_msg_data *) sctx->msg_data;
|
|
|
|
if (msg->pamh && msg->ctrl)
|
|
opensc_pam_msg(msg->pamh, *msg->ctrl, PAM_TEXT_INFO, str);
|
|
}
|
|
|
|
static void logmsg(scam_context * sctx, char *str)
|
|
{
|
|
scam_msg_data *msg = (scam_msg_data *) sctx->msg_data;
|
|
|
|
if (msg->pamh)
|
|
opensc_pam_log(LOG_NOTICE, msg->pamh, "%s", str);
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
int i;
|
|
|
|
printf("pam_opensc: [options]\n\n");
|
|
printf("Generic options:\n");
|
|
printf(" -h Show help\n\n");
|
|
for (i = 0; scam_frameworks[i]; i++) {
|
|
if (scam_frameworks[i]->name && scam_frameworks[i]->usage) {
|
|
printf("auth_method[%s]:\n%s\n", scam_frameworks[i]->name, scam_frameworks[i]->usage());
|
|
}
|
|
}
|
|
}
|
|
|
|
#if (defined(PAM_STATIC) && defined(PAM_SM_AUTH)) || !defined(PAM_STATIC)
|
|
PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
|
|
{
|
|
PAM_CONST char *user = NULL, *password = NULL, *tty = NULL, *service = NULL;
|
|
const char *pinentry = NULL;
|
|
unsigned int ctrl = 0;
|
|
int rv = 0, i = 0;
|
|
scam_msg_data msg = {pamh, &ctrl};
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
if (argv[i][0] == '-') {
|
|
switch (argv[i][1]) {
|
|
case 'h':
|
|
case '?':
|
|
usage();
|
|
return PAM_MAXTRIES;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
ctrl = opensc_pam_set_ctrl(pamh, flags, argc, (const char **) argv);
|
|
memset(&sctx, 0, sizeof(scam_context));
|
|
scam_parse_parameters(&sctx, argc, (const char **) argv);
|
|
sctx.printmsg = printmsg;
|
|
sctx.logmsg = logmsg;
|
|
sctx.msg_data = &msg;
|
|
if (sctx.auth_method) {
|
|
sctx.method = scam_select_by_name(sctx.auth_method);
|
|
free(sctx.auth_method);
|
|
sctx.auth_method = NULL;
|
|
}
|
|
if (sctx.method < 0) {
|
|
return PAM_TRY_AGAIN;
|
|
}
|
|
rv = scam_init(&sctx, argc, (const char **) argv);
|
|
if (rv != SCAM_SUCCESS) {
|
|
scam_deinit(&sctx);
|
|
return PAM_TRY_AGAIN;
|
|
}
|
|
pinentry = scam_pinentry(&sctx);
|
|
|
|
/* Get the username */
|
|
rv = pam_get_user(pamh, &user, "login: ");
|
|
if (rv == PAM_SUCCESS) {
|
|
/*
|
|
* Various libraries at various times have had bugs related to
|
|
* '+' or '-' as the first character of a user name. Don't take
|
|
* any chances here. Require that the username starts with an
|
|
* alphanumeric character.
|
|
*/
|
|
if (!user || !isalnum((int) *user)) {
|
|
opensc_pam_log(LOG_ERR, pamh, "bad username [%s]\n", user);
|
|
rv = PAM_USER_UNKNOWN;
|
|
scam_deinit(&sctx);
|
|
return rv;
|
|
}
|
|
if (rv == PAM_SUCCESS && on(OPENSC_DEBUG, ctrl)) {
|
|
opensc_pam_log(LOG_DEBUG, pamh, "username [%s] obtained\n", user);
|
|
}
|
|
} else {
|
|
opensc_pam_log(LOG_DEBUG, pamh, "trouble reading username\n");
|
|
if (rv == PAM_CONV_AGAIN) {
|
|
opensc_pam_log(LOG_DEBUG, pamh, "pam_get_user/conv() function is not ready yet\n");
|
|
/* it is safe to resume this function so we translate this
|
|
* rv to the value that indicates we're happy to resume.
|
|
*/
|
|
rv = PAM_INCOMPLETE;
|
|
}
|
|
scam_deinit(&sctx);
|
|
return rv;
|
|
}
|
|
/* Check tty */
|
|
rv = pam_get_item(pamh, PAM_TTY, (PAM_CONST void **) &tty);
|
|
/* Get the name of the service */
|
|
rv = pam_get_item(pamh, PAM_SERVICE, (PAM_CONST void **) &service);
|
|
if (rv != PAM_SUCCESS) {
|
|
scam_deinit(&sctx);
|
|
return rv;
|
|
}
|
|
/* get this user's authentication token */
|
|
rv = opensc_pam_read_password(pamh, ctrl, NULL, (PAM_CONST char *) (pinentry ? pinentry : DEFAULT_PINENTRY), NULL, _PAM_AUTHTOK, &password);
|
|
if (rv != PAM_SUCCESS) {
|
|
if (rv != PAM_CONV_AGAIN) {
|
|
opensc_pam_log(LOG_CRIT, pamh, "auth could not identify password for [%s]\n", user);
|
|
} else {
|
|
opensc_pam_log(LOG_DEBUG, pamh, "conversation function is not ready yet\n");
|
|
/*
|
|
* it is safe to resume this function so we translate this
|
|
* rv to the value that indicates we're happy to resume.
|
|
*/
|
|
rv = PAM_INCOMPLETE;
|
|
}
|
|
user = NULL;
|
|
scam_deinit(&sctx);
|
|
return rv;
|
|
}
|
|
if (!user) {
|
|
scam_deinit(&sctx);
|
|
return PAM_USER_UNKNOWN;
|
|
}
|
|
if (!tty) {
|
|
tty = "";
|
|
}
|
|
if (!service || !password) {
|
|
scam_deinit(&sctx);
|
|
return PAM_AUTH_ERR;
|
|
}
|
|
#if 1
|
|
/* No remote logins allowed through xdm */
|
|
if ((!strcmp(service, "xdm") &&
|
|
strcmp(tty, ":0"))) {
|
|
char buf[256];
|
|
|
|
snprintf(buf, 256, "User %s (tty %s) tried remote login through service %s, permission denied.\n", user, tty, service);
|
|
opensc_pam_log(LOG_NOTICE, pamh, buf);
|
|
scam_deinit(&sctx);
|
|
return PAM_PERM_DENIED;
|
|
}
|
|
#endif
|
|
|
|
rv = scam_qualify(&sctx, (unsigned char *) password);
|
|
if (rv != SCAM_SUCCESS) {
|
|
pam_set_item(pamh, PAM_AUTHTOK, password);
|
|
scam_deinit(&sctx);
|
|
return PAM_TRY_AGAIN;
|
|
}
|
|
rv = scam_auth(&sctx, argc, (const char **) argv, user, password);
|
|
scam_deinit(&sctx);
|
|
if (rv != SCAM_SUCCESS) {
|
|
opensc_pam_log(LOG_INFO, pamh, "Authentication failed for %s at %s.\n", user, tty);
|
|
return PAM_AUTH_ERR;
|
|
}
|
|
opensc_pam_log(LOG_INFO, pamh, "Authentication successful for %s at %s.\n", user, tty);
|
|
return PAM_SUCCESS;
|
|
}
|
|
|
|
PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags, int argc,
|
|
const char **argv)
|
|
{
|
|
return PAM_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#if (defined(PAM_STATIC) && defined(PAM_SM_ACCOUNT)) || !defined(PAM_STATIC)
|
|
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, int argc,
|
|
const char **argv)
|
|
{
|
|
return PAM_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#if (defined(PAM_STATIC) && defined(PAM_SM_SESSION)) || !defined(PAM_STATIC)
|
|
PAM_EXTERN int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc,
|
|
const char **argv)
|
|
{
|
|
PAM_CONST char *user = NULL, *service = NULL;
|
|
unsigned int ctrl = 0;
|
|
int rv = 0;
|
|
scam_msg_data msg = {pamh, &ctrl};
|
|
|
|
ctrl = opensc_pam_set_ctrl(pamh, flags, argc, argv);
|
|
memset(&sctx, 0, sizeof(scam_context));
|
|
scam_parse_parameters(&sctx, argc, (const char **) argv);
|
|
sctx.printmsg = printmsg;
|
|
sctx.logmsg = logmsg;
|
|
sctx.msg_data = &msg;
|
|
if (sctx.auth_method) {
|
|
sctx.method = scam_select_by_name(sctx.auth_method);
|
|
free(sctx.auth_method);
|
|
sctx.auth_method = NULL;
|
|
}
|
|
if (sctx.method < 0) {
|
|
return PAM_SESSION_ERR;
|
|
}
|
|
rv = pam_get_item(pamh, PAM_USER, (PAM_CONST void **) &user);
|
|
if (!user || rv != PAM_SUCCESS) {
|
|
opensc_pam_log(LOG_CRIT, pamh, "open_session - error recovering username\n");
|
|
return PAM_SESSION_ERR; /* How did we get authenticated with no username?! */
|
|
}
|
|
if (on(OPENSC_DEBUG, ctrl))
|
|
opensc_pam_log(LOG_INFO, pamh, "Pam user name %s\n", user);
|
|
rv = pam_get_item(pamh, PAM_SERVICE, (PAM_CONST void **) &service);
|
|
if (!service || rv != PAM_SUCCESS) {
|
|
opensc_pam_log(LOG_CRIT, pamh, "open_session - error recovering service\n");
|
|
return PAM_SESSION_ERR;
|
|
}
|
|
rv = scam_open_session(&sctx, argc, (const char **) argv, user);
|
|
if (rv != SCAM_SUCCESS) {
|
|
opensc_pam_log(LOG_CRIT, pamh, "open_session - scam_open_session failed\n");
|
|
return PAM_SESSION_ERR;
|
|
}
|
|
opensc_pam_log(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)\n", user, opensc_pam_get_login() == NULL ? "" : opensc_pam_get_login(), getuid());
|
|
return PAM_SUCCESS;
|
|
}
|
|
|
|
PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc,
|
|
const char **argv)
|
|
{
|
|
PAM_CONST char *user = NULL, *service = NULL;
|
|
unsigned int ctrl = 0;
|
|
int rv = 0;
|
|
scam_msg_data msg = {pamh, &ctrl};
|
|
|
|
ctrl = opensc_pam_set_ctrl(pamh, flags, argc, argv);
|
|
memset(&sctx, 0, sizeof(scam_context));
|
|
scam_parse_parameters(&sctx, argc, (const char **) argv);
|
|
sctx.printmsg = printmsg;
|
|
sctx.logmsg = logmsg;
|
|
sctx.msg_data = &msg;
|
|
if (sctx.auth_method) {
|
|
sctx.method = scam_select_by_name(sctx.auth_method);
|
|
free(sctx.auth_method);
|
|
sctx.auth_method = NULL;
|
|
}
|
|
if (sctx.method < 0) {
|
|
return PAM_SESSION_ERR;
|
|
}
|
|
rv = pam_get_item(pamh, PAM_USER, (PAM_CONST void **) &user);
|
|
if (!user || rv != PAM_SUCCESS) {
|
|
opensc_pam_log(LOG_CRIT, pamh, "close_session - error recovering username\n");
|
|
return PAM_SESSION_ERR; /* How did we get authenticated with no username?! */
|
|
}
|
|
rv = pam_get_item(pamh, PAM_SERVICE, (PAM_CONST void **) &service);
|
|
if (!service || rv != PAM_SUCCESS) {
|
|
opensc_pam_log(LOG_CRIT, pamh, "close_session - error recovering service\n");
|
|
return PAM_SESSION_ERR;
|
|
}
|
|
rv = scam_close_session(&sctx, argc, (const char **) argv, user);
|
|
if (rv != SCAM_SUCCESS) {
|
|
opensc_pam_log(LOG_CRIT, pamh, "open_session - scam_close_session failed\n");
|
|
return PAM_SESSION_ERR;
|
|
}
|
|
opensc_pam_log(LOG_INFO, pamh, "session closed for user %s\n", user);
|
|
return PAM_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#if (defined(PAM_STATIC) && defined(PAM_SM_PASSWORD)) || !defined(PAM_STATIC)
|
|
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc,
|
|
const char **argv)
|
|
{
|
|
return PAM_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#ifdef PAM_STATIC
|
|
struct pam_module _pam_opensc_modstruct =
|
|
{
|
|
"pam_opensc",
|
|
pam_sm_authenticate,
|
|
pam_sm_setcred,
|
|
NULL,
|
|
pam_sm_open_session,
|
|
pam_sm_close_session,
|
|
NULL,
|
|
};
|
|
#endif
|