pam module obsoleted by pam_pkcs11 and pam_p11.

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2416 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
aj 2005-07-17 20:08:06 +00:00
parent 841694817c
commit 7de8272675
24 changed files with 2 additions and 5344 deletions

View File

@ -986,16 +986,12 @@ src/libopensc/libscam.pc
src/libopensc/libscconf.pc
src/libopensc/libscldap.pc
src/openssh/Makefile
src/pam/Makefile
src/pkcs11/Makefile
src/pkcs11/rsaref/Makefile
src/pkcs15init/Makefile
src/scam/Makefile
src/scconf/Makefile
src/scdl/Makefile
src/scldap/Makefile
src/scrandom/Makefile
src/sia/Makefile
src/signer/Makefile
src/signer/npinclude/Makefile
src/libp11/Makefile

View File

@ -5,5 +5,5 @@ MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = Makefile.mak
# Order IS important
SUBDIRS = common include scconf scdl scldap scrandom libopensc pkcs15init pkcs11 \
tests tools openssh scam pam sia signer libp11 sslengines
SUBDIRS = common include scconf scdl scrandom libopensc pkcs15init pkcs11 \
tests tools openssh signer libp11 sslengines

View File

@ -1,20 +0,0 @@
# Process this file with automake to create Makefile.in
libdir = @libdir@/security
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = @CPPFLAGS@ -I${top_srcdir}/src/scam
AM_LDFLAGS = ${top_builddir}/src/scam/libscam.la
if HAVE_PAM
lib_LTLIBRARIES = pam_opensc.la
noinst_PROGRAMS = test-pam
endif
pam_opensc_la_SOURCES = pam_opensc.c pam_support.c pam_support.h
pam_opensc_la_LDFLAGS = -module -avoid-version
test_pam_SOURCES = test-pam.c misc_conv.c
test_pam_LDFLAGS = @LDFLAGS@ @LIBDL@ @LIBPAM@

View File

@ -1,294 +0,0 @@
/*
* $Id$
*
* A generic conversation function for text based applications
*
* Written by Andrew Morgan <morgan@linux.kernel.org>
* Slightly modified for pam_opensc-test by Antti Tapaninen <aet@cc.hut.fi>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <termios.h>
#include <time.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SECURITY_PAM_APPL_H
#include <security/pam_appl.h>
#else
#include <pam/pam_appl.h>
#endif
#include "pam_support.h"
#undef D
#define D(x)
#define INPUTSIZE PAM_MAX_MSG_SIZE /* maximum length of input+1 */
#define CONV_ECHO_ON 1 /* types of echo state */
#define CONV_ECHO_OFF 0
/*
* external timeout definitions - these can be overriden by the
* application.
*/
time_t pam_misc_conv_warn_time = 0; /* time when we warn */
time_t pam_misc_conv_die_time = 0; /* time when we timeout */
const char *pam_misc_conv_warn_line = "..\a.Time is running out...\n";
const char *pam_misc_conv_die_line = "..\a.Sorry, your time is up!\n";
int pam_misc_conv_died = 0; /* application can probe this for timeout */
/* the following code is used to get text input */
volatile static int expired = 0;
/* return to the previous signal handling */
static void reset_alarm(struct sigaction *o_ptr)
{
(void) alarm(0); /* stop alarm clock - if still ticking */
(void) sigaction(SIGALRM, o_ptr, NULL);
}
/* this is where we intercept the alarm signal */
static void time_is_up(int ignore)
{
expired = 1;
}
/* set the new alarm to hit the time_is_up() function */
static int set_alarm(int delay, struct sigaction *o_ptr)
{
struct sigaction new_sig;
sigemptyset(&new_sig.sa_mask);
new_sig.sa_flags = 0;
new_sig.sa_handler = time_is_up;
if (sigaction(SIGALRM, &new_sig, o_ptr)) {
return 1; /* setting signal failed */
}
if (alarm(delay)) {
(void) sigaction(SIGALRM, o_ptr, NULL);
return 1; /* failed to set alarm */
}
return 0; /* all seems to have worked */
}
/* return the number of seconds to next alarm. 0 = no delay, -1 = expired */
static int get_delay(void)
{
time_t now;
expired = 0; /* reset flag */
(void) time(&now);
/* has the quit time past? */
if (pam_misc_conv_die_time && now >= pam_misc_conv_die_time) {
fprintf(stderr, "%s", pam_misc_conv_die_line);
pam_misc_conv_died = 1; /* note we do not reset the die_time */
return -1; /* time is up */
}
/* has the warning time past? */
if (pam_misc_conv_warn_time && now >= pam_misc_conv_warn_time) {
fprintf(stderr, "%s", pam_misc_conv_warn_line);
pam_misc_conv_warn_time = 0; /* reset warn_time */
/* indicate remaining delay - if any */
return (pam_misc_conv_die_time ? pam_misc_conv_die_time - now : 0);
}
/* indicate possible warning delay */
if (pam_misc_conv_warn_time)
return (pam_misc_conv_warn_time - now);
else if (pam_misc_conv_die_time)
return (pam_misc_conv_die_time - now);
else
return 0;
}
/* read a line of input string, giving prompt when appropriate */
static char *read_string(int echo, const char *prompt)
{
struct termios term_before, term_tmp;
char line[INPUTSIZE];
struct sigaction old_sig;
int delay, nc, have_term = 0;
D(("called with echo='%s', prompt='%s'.", echo ? "ON" : "OFF", prompt));
if (isatty(STDIN_FILENO)) { /* terminal state */
/* is a terminal so record settings and flush it */
if (tcgetattr(STDIN_FILENO, &term_before) != 0) {
D(("<error: failed to get terminal settings>"));
return NULL;
}
memcpy(&term_tmp, &term_before, sizeof(term_tmp));
if (!echo) {
term_tmp.c_lflag &= ~(ECHO);
}
have_term = 1;
} else if (!echo) {
D(("<warning: cannot turn echo off>"));
}
/* set up the signal handling */
delay = get_delay();
/* reading the line */
while (delay >= 0) {
fprintf(stderr, "%s", prompt);
/* this may, or may not set echo off -- drop pending input */
if (have_term)
(void) tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_tmp);
if (delay > 0 && set_alarm(delay, &old_sig)) {
D(("<failed to set alarm>"));
break;
} else {
nc = read(STDIN_FILENO, line, INPUTSIZE - 1);
if (have_term) {
(void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before);
if (!echo || expired) /* do we need a newline? */
fprintf(stderr, "\n");
}
if (delay > 0) {
reset_alarm(&old_sig);
}
if (expired) {
delay = get_delay();
} else if (nc > 0) { /* we got some user input */
char *input;
if (nc > 0 && line[nc - 1] == '\n') { /* <NUL> terminate */
line[--nc] = '\0';
} else {
line[nc] = '\0';
}
input = x_strdup(line);
_pam_overwrite(line);
return input; /* return malloc()ed string */
} else if (nc == 0) { /* Ctrl-D */
D(("user did not want to type anything"));
fprintf(stderr, "\n");
break;
}
}
}
/* getting here implies that the timer expired */
if (have_term)
(void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before);
memset(line, 0, INPUTSIZE); /* clean up */
return NULL;
}
/* end of read_string functions */
int misc_conv(int num_msg, const struct pam_message **msgm,
struct pam_response **response, void *appdata_ptr)
{
int count = 0;
struct pam_response *reply;
if (num_msg <= 0)
return PAM_CONV_ERR;
D(("allocating empty response structure array."));
reply = (struct pam_response *) calloc(num_msg,
sizeof(struct pam_response));
if (reply == NULL) {
D(("no memory for responses"));
return PAM_CONV_ERR;
}
D(("entering conversation function."));
for (count = 0; count < num_msg; ++count) {
char *string = NULL;
switch (msgm[count]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
string = read_string(CONV_ECHO_OFF, msgm[count]->msg);
if (string == NULL) {
goto failed_conversation;
}
break;
case PAM_PROMPT_ECHO_ON:
string = read_string(CONV_ECHO_ON, msgm[count]->msg);
if (string == NULL) {
goto failed_conversation;
}
break;
case PAM_ERROR_MSG:
if (fprintf(stderr, "%s\n", msgm[count]->msg) < 0) {
goto failed_conversation;
}
break;
case PAM_TEXT_INFO:
if (fprintf(stdout, "%s\n", msgm[count]->msg) < 0) {
goto failed_conversation;
}
break;
default:
fprintf(stderr, "erroneous conversation (%d)\n"
,msgm[count]->msg_style);
goto failed_conversation;
}
if (string) { /* must add to reply array */
/* add string to list of responses */
reply[count].resp_retcode = 0;
reply[count].resp = string;
string = NULL;
}
}
/* New (0.59+) behavior is to always have a reply - this is
compatable with the X/Open (March 1997) spec. */
*response = reply;
reply = NULL;
return PAM_SUCCESS;
failed_conversation:
if (reply) {
for (count = 0; count < num_msg; ++count) {
if (reply[count].resp == NULL) {
continue;
}
switch (msgm[count]->msg_style) {
case PAM_PROMPT_ECHO_ON:
case PAM_PROMPT_ECHO_OFF:
_pam_overwrite(reply[count].resp);
free(reply[count].resp);
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
/* should not actually be able to get here... */
free(reply[count].resp);
}
reply[count].resp = NULL;
}
/* forget reply too */
free(reply);
reply = NULL;
}
return PAM_CONV_ERR;
}

View File

@ -1,334 +0,0 @@
/*
* $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

View File

@ -1,394 +0,0 @@
/*
* $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 <stdarg.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <pwd.h>
#include <grp.h>
#ifdef HAVE_UTMP_H
#include <utmp.h>
#endif
#include <sys/types.h>
#include "pam_support.h"
void opensc_pam_log(int err, pam_handle_t * pamh, const char *format,...)
{
char logname[256], *service = NULL;
va_list args;
pam_get_item(pamh, PAM_SERVICE, (PAM_CONST void **) &service);
if (service) {
strncpy(logname, service, sizeof(logname));
logname[sizeof(logname) - 1 - strlen("(pam_opensc)")] = '\0';
strncat(logname, "(pam_opensc)", strlen("(pam_opensc)"));
} else {
strncpy(logname, "pam_opensc", sizeof(logname) - 1);
}
openlog(logname, LOG_CONS | LOG_PID, LOG_AUTH);
va_start(args, format);
#ifdef HAVE_VSYSLOG
vsyslog(err, format, args);
#else
{
char buf[256];
memset(buf, 0, sizeof(buf));
vsnprintf(buf, sizeof(buf), format, args);
syslog(err, "%s", buf);
}
#endif
va_end(args);
closelog();
}
/* this is a front-end for module-application conversations */
static int converse(pam_handle_t * pamh, int ctrl, int nargs
,struct pam_message **message
,struct pam_response **response)
{
int retval;
struct pam_conv *conv;
retval = pam_get_item(pamh, PAM_CONV, (PAM_CONST void **) &conv);
if (!conv && retval == PAM_SUCCESS) {
/* XXX: I have no idea why this happens in some cases */
retval = PAM_SYSTEM_ERR;
}
if (retval == PAM_SUCCESS) {
retval = conv->conv(nargs, (PAM_CONST struct pam_message **) message
,response, conv->appdata_ptr);
if (retval != PAM_SUCCESS && on(OPENSC_DEBUG, ctrl)) {
opensc_pam_log(LOG_DEBUG, pamh, "conversation failure [%s]"
,pam_strerror(pamh, retval));
}
} else if (retval != PAM_CONV_AGAIN) {
opensc_pam_log(LOG_ERR, pamh
,"couldn't obtain conversation function [%s]"
,pam_strerror(pamh, retval));
}
return retval; /* propagate error status */
}
int opensc_pam_msg(pam_handle_t * pamh, unsigned int ctrl
,int type, PAM_CONST char *text)
{
int retval = PAM_SUCCESS;
if (off(OPENSC__QUIET, ctrl)) {
struct pam_message *pmsg[1], msg[1];
struct pam_response *resp;
char *buf = strdup(text);
unsigned int i;
if (!buf) {
return PAM_BUF_ERR;
}
pmsg[0] = &msg[0];
for (i = 0; i < strlen(buf); i++) {
if (buf[i] == '\n') {
buf[i] = '\0';
}
}
msg[0].msg = buf;
msg[0].msg_style = type;
resp = NULL;
retval = converse(pamh, ctrl, 1, pmsg, &resp);
free(buf);
if (resp) {
_pam_drop_reply(resp, 1);
}
}
return retval;
}
static void print_ctrl(unsigned int ctrl)
{
unsigned int i;
for (i = 0; i < OPENSC_CTRLS_; i++) {
if (on(i, ctrl)) {
printf("ctrl[%02i] = enabled\n", i);
} else {
printf("ctrl[%02i] = disabled\n", i);
}
}
}
/*
* set the control flags for the OPENSC module.
*/
int opensc_pam_set_ctrl(pam_handle_t * pamh, int flags, int argc, const char **argv)
{
unsigned int ctrl;
ctrl = OPENSC_DEFAULTS; /* the default selection of options */
/* set some flags manually */
if (getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
set(OPENSC__IAMROOT, ctrl);
}
if (flags & PAM_UPDATE_AUTHTOK) {
set(OPENSC__UPDATE, ctrl);
}
if (flags & PAM_PRELIM_CHECK) {
set(OPENSC__PRELIM, ctrl);
}
if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
set(OPENSC__NONULL, ctrl);
}
if (flags & PAM_SILENT) {
set(OPENSC__QUIET, ctrl);
}
/* now parse the arguments to this module */
while (argc-- > 0) {
int j;
for (j = 0; j < OPENSC_CTRLS_; ++j) {
if (opensc_args[j].token
&& !strncmp(*argv, opensc_args[j].token, strlen(opensc_args[j].token))) {
break;
}
}
if (j >= OPENSC_CTRLS_) {
#if 0
opensc_pam_log(LOG_ERR, pamh,
"unrecognized option [%s]", *argv);
#endif
} else {
ctrl &= opensc_args[j].mask; /* for turning things off */
ctrl |= opensc_args[j].flag; /* for turning things on */
}
++argv; /* step to next argument */
}
/* auditing is a more sensitive version of debug */
if (on(OPENSC_AUDIT, ctrl)) {
set(OPENSC_DEBUG, ctrl);
}
if (on(OPENSC_DEBUG, ctrl)) {
print_ctrl(ctrl);
}
/* return the set of flags */
return ctrl;
}
static void _cleanup(pam_handle_t * pamh, void *x, int error_status)
{
char *y = (char *) x;
_pam_delete(y);
}
/* ************************************************************** *
* Useful non-trivial functions *
* ************************************************************** */
/*
* obtain a password from the user
*/
int opensc_pam_read_password(pam_handle_t * pamh
,unsigned int ctrl
,PAM_CONST char *comment
,PAM_CONST char *prompt1
,PAM_CONST char *prompt2
,PAM_CONST char *data_name
,PAM_CONST char **pass)
{
int authtok_flag, retval;
PAM_CONST char *item = NULL;
char *token = NULL;
/*
* which authentication token are we getting?
*/
authtok_flag = on(OPENSC__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
/*
* should we obtain the password from a PAM item ?
*/
if (on(OPENSC_TRY_FIRST_PASS, ctrl) || on(OPENSC_USE_FIRST_PASS, ctrl)) {
retval = pam_get_item(pamh, authtok_flag, (PAM_CONST void **) &item);
if (retval != PAM_SUCCESS) {
/* very strange. */
opensc_pam_log(LOG_ALERT, pamh, "pam_get_item returned error to read-password");
return retval;
} else if (item != NULL) { /* we have a password! */
*pass = item;
item = NULL;
return PAM_SUCCESS;
} else if (on(OPENSC_USE_FIRST_PASS, ctrl)) {
return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
} else if (on(OPENSC_USE_AUTHTOK, ctrl)
&& off(OPENSC__OLD_PASSWD, ctrl)) {
return PAM_AUTHTOK_RECOVER_ERR;
}
}
/*
* getting here implies we will have to get the password from the
* user directly.
*/
{
struct pam_message msg[3], *pmsg[3];
struct pam_response *resp;
int i, replies;
/* prepare to converse */
if (comment != NULL && off(OPENSC__QUIET, ctrl)) {
pmsg[0] = &msg[0];
msg[0].msg_style = PAM_TEXT_INFO;
msg[0].msg = comment;
i = 1;
} else {
i = 0;
}
pmsg[i] = &msg[i];
msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
msg[i++].msg = prompt1;
replies = 1;
if (prompt2 != NULL) {
pmsg[i] = &msg[i];
msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
msg[i++].msg = prompt2;
++replies;
}
/* so call the conversation expecting i responses */
resp = NULL;
retval = converse(pamh, ctrl, i, pmsg, &resp);
if (resp != NULL) {
/* interpret the response */
if (retval == PAM_SUCCESS) { /* a good conversation */
token = x_strdup(resp[i - replies].resp);
if (token != NULL) {
if (replies == 2) {
/* verify that password entered correctly */
if (!resp[i - 1].resp || strcmp(token, resp[i - 1].resp)) {
_pam_delete(token); /* mistyped */
retval = PAM_AUTHTOK_RECOVER_ERR;
opensc_pam_msg(pamh, ctrl, PAM_ERROR_MSG, MISTYPED_PASS);
}
}
} else {
opensc_pam_log(LOG_NOTICE, pamh, "could not recover authentication token");
}
}
/*
* tidy up the conversation (resp_retcode) is ignored
* -- what is it for anyway? AGM
*/
_pam_drop_reply(resp, i);
} else {
retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval;
}
}
if (retval != PAM_SUCCESS) {
if (on(OPENSC_DEBUG, ctrl))
opensc_pam_log(LOG_DEBUG, pamh,
"unable to obtain a password");
return retval;
}
/* 'token' is the entered password */
if (on(OPENSC_SET_PASS, ctrl)) {
/* we store this password as an item */
retval = pam_set_item(pamh, authtok_flag, token);
_pam_delete(token); /* clean it up */
if (retval != PAM_SUCCESS || (retval = pam_get_item(pamh, authtok_flag, (PAM_CONST void **) &item)) != PAM_SUCCESS) {
opensc_pam_log(LOG_CRIT, pamh, "error manipulating password");
return retval;
}
} else {
/*
* then store it as data specific to this module. pam_end()
* will arrange to clean it up.
*/
retval = pam_set_data(pamh, data_name, (void *) token, _cleanup);
if (retval != PAM_SUCCESS) {
opensc_pam_log(LOG_CRIT, pamh
,"error manipulating password data [%s]"
,pam_strerror(pamh, retval));
_pam_delete(token);
return retval;
}
item = token;
token = NULL; /* break link to password */
}
*pass = item;
item = NULL; /* break link to password */
return PAM_SUCCESS;
}
/*
* Because getlogin() is braindead and sometimes it just
* doesn't work, we reimplement it here.
*/
char *opensc_pam_get_login(void)
{
char *user = NULL;
#ifdef HAVE_SETUTENT
struct utmp *ut = NULL, line;
static char curr_user[sizeof(ut->ut_user) + 4];
char *curr_tty = NULL;
curr_tty = ttyname(0);
if (curr_tty) {
curr_tty += 5;
setutent();
strncpy(line.ut_line, curr_tty, sizeof line.ut_line);
if ((ut = getutline(&line))) {
strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user));
user = curr_user;
}
endutent();
}
#else
user = getlogin();
#endif
#if 1
if (!user) {
struct passwd *pw_user = getpwuid(geteuid());
user = pw_user->pw_name;
}
#endif
return user;
}

View File

@ -1,209 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2001, 2002
* Antti Tapaninen <aet@cc.hut.fi>
* Anna Erika Suortti <asuortti@cc.hut.fi>
*
* Taken and modified from the pam_unix source
*
* 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.
*/
#ifndef _PAM_SUPPORT_H
#define _PAM_SUPPORT_H
#include <syslog.h>
#ifdef HAVE_SECURITY_PAM_APPL_H
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#else
#include <pam/pam_appl.h>
#include <pam/pam_modules.h>
#endif
#ifdef HAVE_SECURITY__PAM_MACROS_H
#include <security/_pam_macros.h>
#elif HAVE_PAM__PAM_MACROS_H
#include <pam/_pam_macros.h>
#else
#define x_strdup(s) ((s) ? strdup(s):NULL)
#define _pam_overwrite(x) \
do { \
register char *__xx__; \
if ((__xx__=(x))) \
while (*__xx__) \
*__xx__++ = '\0'; \
} while (0)
#define _pam_drop(X) \
do { \
if (X) { \
free(X); \
X=NULL; \
} \
} while (0)
#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
do { \
int reply_i; \
\
for (reply_i=0; reply_i<replies; ++reply_i) { \
if (reply[reply_i].resp) { \
_pam_overwrite(reply[reply_i].resp); \
free(reply[reply_i].resp); \
} \
} \
if (reply) \
free(reply); \
} while (0)
#endif
#ifndef PAM_EXTERN
#define PAM_EXTERN
#endif
#ifdef PAM_SUN_CODEBASE
#define PAM_CONST
#else
#define PAM_CONST const
#endif
#ifndef PAM_CONV_AGAIN
#define PAM_CONV_AGAIN PAM_TRY_AGAIN
#endif
#ifndef PAM_INCOMPLETE
#define PAM_INCOMPLETE PAM_TRY_AGAIN
#endif
#ifndef PAM_AUTHTOK_RECOVER_ERR
#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* here is the string to inform the user that the new passwords they
* typed were not the same.
*/
#define DEFAULT_PINENTRY "Enter PIN1: "
#define MISTYPED_PASS "Sorry, passwords do not match"
/* type definition for the control options */
typedef struct {
const char *token;
unsigned int mask; /* shall assume 32 bits of flags */
unsigned int flag;
} OPENSC_Ctrls;
/*
* macro to determine if a given flag is on
*/
#define on(x,ctrl) (opensc_args[x].flag & ctrl)
/*
* macro to determine that a given flag is NOT on
*/
#define off(x,ctrl) (!on(x,ctrl))
/*
* macro to turn on/off a ctrl flag manually
*/
#define set(x,ctrl) (ctrl = ((ctrl)&opensc_args[x].mask)|opensc_args[x].flag)
#define unset(x,ctrl) (ctrl &= ~(opensc_args[x].flag))
/* the generic mask */
#define _ALL_ON_ (~0U)
/* end of macro definitions definitions for the control flags */
/* ****************************************************************** *
* ctrl flags proper..
*/
/*
* here are the various options recognized by the opensc module. They
* are enumerated here and then defined below. Internal arguments are
* given NULL tokens.
*/
#define OPENSC__OLD_PASSWD 0 /* internal */
#define OPENSC__VERIFY_PASSWD 1 /* internal */
#define OPENSC__IAMROOT 2 /* internal */
#define OPENSC_AUDIT 3 /* print more things than debug..
some information may be sensitive */
#define OPENSC_USE_FIRST_PASS 4
#define OPENSC_TRY_FIRST_PASS 5
#define OPENSC_SET_PASS 6 /* set AUTHTOK items */
#define OPENSC__PRELIM 7 /* internal */
#define OPENSC__UPDATE 8 /* internal */
#define OPENSC__NONULL 9 /* internal */
#define OPENSC__QUIET 10 /* internal */
#define OPENSC_USE_AUTHTOK 11 /* insist on reading PAM_AUTHTOK */
#define OPENSC_DEBUG 12 /* send more info to syslog(3) */
/* -------------- */
#define OPENSC_CTRLS_ 13 /* number of ctrl arguments defined */
static const OPENSC_Ctrls opensc_args[OPENSC_CTRLS_] =
{
/* symbol token name ctrl mask ctrl *
* ----------------------- ------------------- --------------------- -------- */
/* OPENSC__OLD_PASSWD */ {NULL, _ALL_ON_, 01},
/* OPENSC__VERIFY_PASSWD */ {NULL, _ALL_ON_, 02},
/* OPENSC__IAMROOT */ {NULL, _ALL_ON_, 04},
/* OPENSC_AUDIT */ {"audit", _ALL_ON_, 010},
/* OPENSC_USE_FIRST_PASS */ {"use_first_pass", _ALL_ON_, 020},
/* OPENSC_TRY_FIRST_PASS */ {"try_first_pass", _ALL_ON_, 040},
/* OPENSC_SET_PASS */ {"set_pass", _ALL_ON_, 0100},
/* OPENSC__PRELIM */ {NULL, _ALL_ON_, 0200},
/* OPENSC__UPDATE */ {NULL, _ALL_ON_, 0400},
/* OPENSC__NONULL */ {NULL, _ALL_ON_, 01000},
/* OPENSC__QUIET */ {NULL, _ALL_ON_, 02000},
/* OPENSC_USE_AUTHTOK */ {"use_authtok", _ALL_ON_, 04000},
/* OPENSC_DEBUG */ {"debug", _ALL_ON_, 010000},
};
#define OPENSC_DEFAULTS (opensc_args[OPENSC__NONULL].flag)
/* use this to free strings. ESPECIALLY password strings */
#define _pam_delete(xx) \
{ \
_pam_overwrite(xx); \
_pam_drop(xx); \
}
extern void opensc_pam_log(int err, pam_handle_t * pamh, const char *format,...);
extern int opensc_pam_msg(pam_handle_t * pamh, unsigned int ctrl, int type, PAM_CONST char *text);
extern int opensc_pam_set_ctrl(pam_handle_t * pamh, int flags, int argc, const char **argv);
extern int opensc_pam_read_password(pam_handle_t * pamh
,unsigned int ctrl
,PAM_CONST char *comment
,PAM_CONST char *prompt1
,PAM_CONST char *prompt2
,PAM_CONST char *data_name
,PAM_CONST char **pass);
extern char *opensc_pam_get_login(void);
#define _PAM_AUTHTOK "-OPENSC-PASS"
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,87 +0,0 @@
/*
* $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_opensc.c"
#include "pam_support.c"
extern int misc_conv(int num_msg, PAM_CONST struct pam_message **msgm, struct pam_response **response, void *appdata_ptr);
int main(int argc, char **argv)
{
pam_handle_t *pamh = NULL;
struct pam_conv conv =
{
misc_conv,
NULL
};
int flags = 0, count = 3, rv = PAM_AUTH_ERR;
const char *user = getenv("USER");
if (!user) {
printf("No $USER found.\n");
}
do {
rv = pam_start("test", user, &conv, &pamh);
fprintf(stderr, "[%02i] pam_start: %d\n", count, rv);
if (rv == PAM_SUCCESS) {
rv = pam_sm_authenticate(pamh, flags, argc, (const char **) argv);
fprintf(stderr, "[%02i] pam_sm_authenticate: %d\n", count, rv);
}
if (rv == PAM_MAXTRIES) {
pam_end(pamh, rv);
break;
}
if (rv == PAM_SUCCESS) {
fprintf(stderr, "Authenticated\n");
} else {
fprintf(stderr, "Authentication failed.\n");
}
if (rv == PAM_SUCCESS) {
rv = pam_sm_acct_mgmt(pamh, flags, argc, (const char **) argv);
fprintf(stderr, "[%02i] pam_sm_acct_mgmt: %d\n", count, rv);
}
if (rv == PAM_SUCCESS) {
rv = pam_sm_open_session(pamh, flags, argc, (const char **) argv);
fprintf(stderr, "[%02i] pam_sm_open_session: %d\n", count, rv);
}
if (rv == PAM_SUCCESS) {
rv = pam_sm_close_session(pamh, flags, argc, (const char **) argv);
fprintf(stderr, "[%02i] pam_sm_close_session: %d\n", count, rv);
}
if (pam_end(pamh, rv) != PAM_SUCCESS) {
pamh = NULL;
}
count--;
rv = PAM_AUTH_ERR;
} while (count > 0);
return 0;
}

View File

@ -1,14 +0,0 @@
# Process this file with automake to create Makefile.in
MAINTAINERCLEANFILES = Makefile.in
lib_LTLIBRARIES = libscam.la
libscam_la_SOURCES = \
scam.c cert_support.c \
p15_eid.c p15_ldap.c
libscam_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@
libscam_la_LIBADD = @LIBOPENSC@ @LIBCRYPTO@ @LIBSCLDAP@ \
../scrandom/libscrandom.la
noinst_HEADERS = scam.h cert_support.h

View File

@ -1,643 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2001, 2002
* Anna Erika Suortti <asuortti@cc.hut.fi>
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(HAVE_OPENSSL)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include "cert_support.h"
#define CHECK_CTX(ctx, val) \
if (!ctx) { \
return val; \
}
#define CHECK_CTX_VOID(ctx) \
if (!ctx) { \
return; \
}
scCertificate *certAlloc(void)
{
scCertificate *scCert = (scCertificate *) malloc(sizeof(scCertificate));
if (scCert) {
memset(scCert, 0, sizeof(scCertificate));
}
return scCert;
}
static void certFreeBuffer(unsigned char *certbuf)
{
if (certbuf) {
free(certbuf);
}
certbuf = NULL;
}
void certFree(scCertificate * cert)
{
CHECK_CTX_VOID(cert);
if (cert) {
if (cert->pubkey) {
certFreePublicKey(cert->pubkey);
}
cert->pubkey = NULL;
if (cert->crl) {
certFreeCRL(cert->crl);
}
cert->crl = NULL;
if (cert->cert) {
certFreeCertificate(cert->cert);
}
cert->cert = NULL;
if (cert->crlbuf) {
certFreeBuffer(cert->crlbuf);
}
cert->crlbuf = NULL;
cert->crllen = 0;
if (cert->buf) {
certFreeBuffer(cert->buf);
}
cert->buf = NULL;
cert->len = 0;
free(cert);
cert = NULL;
}
}
void certFreeAll(scCertificate ** cert)
{
scCertificate **p = cert;
int i;
CHECK_CTX_VOID(*p);
for (i = 0; p[i]; i++) {
certFree(p[i]);
p[i] = NULL;
}
}
X509 *certParseCertificate(unsigned char *certbuf, unsigned int certlen)
{
X509 *cert = NULL;
unsigned char *certptr = certbuf;
CHECK_CTX(certptr, NULL);
/* Parse DER encoded certificate into the x509 structure */
cert = X509_new();
if (!d2i_X509(&cert, &certptr, certlen)) {
return NULL;
}
return cert;
}
void certFreeCertificate(X509 * cert)
{
CHECK_CTX_VOID(cert);
X509_free(cert);
cert = NULL;
}
X509_CRL *certParseCRL(unsigned char *crlbuf, unsigned int crllen)
{
X509_CRL *crl = NULL;
unsigned char *crlptr = crlbuf;
CHECK_CTX(crlptr, NULL);
/* Parse DER encoded certificate into the x509 crl structure */
crl = X509_CRL_new();
if (!d2i_X509_CRL(&crl, &crlptr, crllen)) {
return NULL;
}
return crl;
}
void certFreeCRL(X509_CRL * crl)
{
CHECK_CTX_VOID(crl);
X509_CRL_free(crl);
crl = NULL;
}
EVP_PKEY *certParsePublicKey(X509 * cert)
{
EVP_PKEY *pubkey = NULL;
CHECK_CTX(cert, NULL);
pubkey = X509_get_pubkey(cert);
return pubkey;
}
void certFreePublicKey(EVP_PKEY * pk)
{
CHECK_CTX_VOID(pk);
EVP_PKEY_free(pk);
pk = NULL;
}
/* This function checks the validity of the certificate given
* in cert and returns 0 if successful and -1 on error.
*/
int certCheckValidity(X509 * cert)
{
CHECK_CTX(cert, -1);
/* Check validity dates against the current time
notBefore < current time and notAfter > current time */
if (X509_cmp_current_time(X509_get_notBefore(cert)) < 0 &&
X509_cmp_current_time(X509_get_notAfter(cert)) > 0) {
return 0;
} else {
if (X509_cmp_current_time(X509_get_notBefore(cert)) > 0) {
#if 0
log_message("Certificate not valid yet\n");
#endif
} else {
#if 0
log_message("Certificate not valid anymore\n");
#endif
}
return -1;
}
return -1;
}
/* This function checks whether the bit bit is set in the keyUsage
* BITSTRING of the certificate given as argument ie. whether
* the key in the certificate is fit for a certain use.
* Returns 1 if set, 0 if not set and -1 on error.
*/
int certCheckKeyUsage(X509 * cert, unsigned int bit)
{
int loc = -1, rv = -1;
ASN1_BIT_STRING *b_asn = NULL;
unsigned char *bitstr = NULL;
X509_EXTENSION *ext = NULL;
CHECK_CTX(cert, -1);
/* keyUsage bits run from 0 to 8 */
if (bit > 8) {
return -1;
}
/* Try to parse keyUsage extension out of the certificate */
loc = X509_get_ext_by_NID(cert, NID_key_usage, -1);
/* No keyUsage existing, bail out */
if (loc < 0) {
return -1;
}
ext = X509_get_ext(cert, loc);
if (!ext) {
return -1;
}
bitstr = ext->value->data;
if (!d2i_ASN1_BIT_STRING(&b_asn, &bitstr, ext->value->length)) {
return -1;
}
if (ASN1_BIT_STRING_get_bit(b_asn, bit)) {
rv = 1;
} else {
rv = 0;
}
ASN1_BIT_STRING_free(b_asn);
return rv;
}
#define ASN1_SEQ 0x30
#define ASN1_CHOICE 0xa0
/* This function parses the CRL distribution point from the
certificate.
Returns CRL location or NULL on error.
*/
char *certGetCRLDistributionPoint(X509 * cert)
{
X509_EXTENSION *ext = NULL;
ASN1_OCTET_STRING *o_asn = NULL;
char *crlbuf = NULL, *distpoint = NULL;
int rv = -1, crllen = 0;
int asnlen = 0, i = 0, j = 0, k = 0;
CHECK_CTX(cert, NULL);
/* Try to parse crlDistributionPoints extension out of the certificate */
rv = X509_get_ext_by_NID(cert, NID_crl_distribution_points, 0);
if (rv < 0) {
return NULL;
}
ext = X509_get_ext(cert, rv);
if (!ext) {
return NULL;
}
o_asn = X509_EXTENSION_get_data(ext);
if (!o_asn) {
return NULL;
}
for (i = 0; i < o_asn->length;) {
switch (*(o_asn->data + i)) {
case ASN1_SEQ:
{
i++;
if (*(o_asn->data + i) & 0x80) {
asnlen = (*(o_asn->data + i) & ~0x80);
i++;
crllen = 0;
for (j = 0; j < asnlen; j++) {
if (j == 0) {
crllen += (*(o_asn->data + i));
} else {
crllen += (j * 0x100) * (*(o_asn->data + i));
}
i++;
}
} else {
i++;
crllen = (*(o_asn->data + i));
}
break;
}
case ASN1_CHOICE:
{
i++;
if (*(o_asn->data + i) & 0x80) {
asnlen = (*(o_asn->data + i) & ~0x80);
i++;
crllen = 0;
for (j = 0; j < asnlen; j++) {
if (j == 0) {
crllen += (*(o_asn->data + i));
} else {
crllen += (j * 0x100) * (*(o_asn->data + i));
}
i++;
}
} else {
i++;
crllen = (*(o_asn->data + i));
i++;
}
for (j = 0; j < crllen; j++) {
if (*(o_asn->data + i) == 0x86) {
i++;
if (*(o_asn->data + i) & 0x80) {
asnlen = (*(o_asn->data + i) & ~0x80);
i++;
crllen = 0;
for (j = 0; j < asnlen; j++) {
if (j == 0) {
crllen += (*(o_asn->data + i));
} else {
crllen += (j * 0x100) * (*(o_asn->data + i));
}
i++;
}
} else {
crllen = (*(o_asn->data + i));
i++;
}
crlbuf = (char *) malloc(crllen + 1);
if (!crlbuf) {
return NULL;
}
memset(crlbuf, 0, crllen + 1);
memcpy(crlbuf, (o_asn->data + i), crllen);
for (k = 0; k < crllen; k++) {
i++;
}
break;
}
i++;
}
break;
}
default:
return NULL;
}
}
distpoint = (char *) malloc(crllen + 1);
if (!distpoint) {
free(crlbuf);
return NULL;
}
memset(distpoint, 0, crllen + 1);
memcpy(distpoint, crlbuf, crllen);
free(crlbuf);
return distpoint;
}
/* This function checks whether the X.509 format certificate cert
is self-signed (ie. issuer and subject names match).
Returns 1 if it is self-signed, 0 if it is not and -1 on error.
*/
int certIsSelfSigned(X509 * cert)
{
CHECK_CTX(cert, -1);
if (!X509_NAME_cmp(X509_get_subject_name(cert), X509_get_issuer_name(cert))) {
return 1;
} else {
return 0;
}
}
#if OPENSSL_VERSION_NUMBER >= 0x00906000L
static char *printDN(X509_NAME *name)
{
char *ret;
int r;
BIO *bp;
bp = BIO_new(BIO_s_mem());
if (!bp)
return NULL;
r = X509_NAME_print_ex(bp, name, 0, XN_FLAG_ONELINE);
if (r < 0) {
BIO_free(bp);
return NULL;
}
ret = (char *) malloc((r + 1) * sizeof(char));
if (!ret) {
BIO_free(bp);
return NULL;
}
BIO_gets(bp, ret, r + 1);
BIO_free(bp);
return ret;
}
#else
static char *printDN(X509_NAME *name)
{
return X509_NAME_oneline(name, NULL, 0);
}
#endif
/* This function returns the issuer of the X.509 format certificate
cert.
*/
char *certGetIssuer(X509 * cert)
{
CHECK_CTX(cert, NULL);
return printDN(X509_get_issuer_name(cert));
}
/* This function returns the subject of the X.509 format certificate
cert.
*/
char *certGetSubject(X509 * cert)
{
CHECK_CTX(cert, NULL);
return printDN(X509_get_subject_name(cert));
}
char *certParseDN(char *entry, char *field)
{
char *token = NULL, *value = NULL, *p = NULL;
CHECK_CTX(entry, NULL);
CHECK_CTX(field, NULL);
token = strtok(entry, "/");
if (!token) {
return NULL;
}
if ((p = strstr(token, field))) {
p = p + strlen(field);
if (*p == '=') {
p++;
}
value = (char *) malloc((strlen(p) + 1) * sizeof(char));
if (!value) {
return NULL;
}
strcpy(value, p);
return value;
}
while ((token = strtok(NULL, "/"))) {
if ((p = strstr(token, field))) {
p = p + strlen(field);
if (*p == '=') {
p++;
}
value = (char *) malloc((strlen(p) + 1) * sizeof(char));
if (!value) {
return NULL;
}
strcpy(value, p);
return value;
}
}
return NULL;
}
/* This function searches the serial number list of a CRL for
serialNumber.
Returns 1 if found, 0 if not found and -1 on error.
*/
static int certIsRevoked(ASN1_STRING * serialNumber, X509_CRL_INFO * crlinfo)
{
int i = 0, numrevoked = 0, revoked = 0;
if (!serialNumber || !crlinfo) {
return -1;
}
numrevoked = sk_num(crlinfo->revoked);
for (i = 0; i < numrevoked && !revoked; i++) {
X509_REVOKED *r = (X509_REVOKED *) sk_value(crlinfo->revoked, i);
if (!ASN1_INTEGER_cmp(serialNumber, r->serialNumber)) {
revoked = 1;
}
}
return revoked;
}
/* This function sets up a certificate store with all the CA certificates
* in X509CAcert and checks the validity and the issuer signature of
* the user certificate and all the CA certificates. This couldn't be
* tested with a real certificate chain, though, as we have none.
* Returns 0 on success and the real openssl error on error (NOTE: these
* are positive integers!).
*/
int certVerifyCAChain(scCertificate ** CAcerts, X509 * cert)
{
scCertificate *currCAcert = CAcerts[0];
X509 *usercert = cert, *x509CAcert = NULL;
ASN1_INTEGER *serialNumber = NULL;
EVP_PKEY *pubkey = NULL;
X509_STORE_CTX cst_ctx;
X509_STORE *cst = NULL;
X509_CRL *x509crl = NULL;
int rv = 0, err = 0, i = 0;
/* There has to be a user certificate and at least one CA certificate */
if (!usercert || !currCAcert) {
return -1;
}
x509CAcert = (X509 *) currCAcert->cert;
if (!x509CAcert) {
#if 0
log_messagex(L_DEBUG, "No CA certs given as argument!\n");
#endif
return -1;
}
/* Set up store */
cst = X509_STORE_new();
if (!cst) {
#if 0
log_messagex(L_DEBUG, "Could not create certificate store, bailing out.\n");
#endif
return -1;
}
/* Add all CA certificates to the store (direction is not
important, openssl should create a chain for us). */
while (x509CAcert) {
rv = X509_STORE_add_cert(cst, x509CAcert);
/* O joy, sometimes openssl returns 0 for OK and
sometimes for error */
if (!rv) {
/* FIXME: Get real error */
err = 1;
X509_STORE_free(cst);
return err;
}
i++;
currCAcert = CAcerts[i];
if (!currCAcert) {
break;
}
x509CAcert = (X509 *) currCAcert->cert;
}
/* Don't care what algorithm the hash uses, just add everything */
SSLeay_add_all_algorithms();
/* Init check of user certificate against CA certs in store */
X509_STORE_CTX_init(&cst_ctx, cst, usercert, NULL);
rv = X509_verify_cert(&cst_ctx);
if (rv < 0) {
err = -1;
} else {
err = X509_STORE_CTX_get_error(&cst_ctx);
}
X509_STORE_CTX_cleanup(&cst_ctx);
X509_STORE_free(cst);
/* FIXME: Check CRL here by hand, will be in openssl version 0.9.7.
Do nothing fancy for now, because a real CRL check will probably
be implemented in openssl before we need multiple CRLs. */
if (!err) {
serialNumber = X509_get_serialNumber(usercert);
currCAcert = CAcerts[0];
x509crl = (X509_CRL *) currCAcert->crl;
x509CAcert = (X509 *) currCAcert->cert;
i = 0;
while (currCAcert && x509CAcert && x509crl) {
if (!serialNumber) {
err = 1;
break;
}
if (!x509crl->crl || !x509CAcert->cert_info) {
err = 1;
break;
}
#if 0
log_messagex(L_DEBUG, "CA Issuer: %s\n", X509_NAME_oneline(x509CAcert->cert_info->subject, NULL, 0));
log_messagex(L_DEBUG, "CRL Issuer: %s\n", X509_NAME_oneline(x509crl->crl->issuer, NULL, 0));
#endif
#if 1
/* Check that CRL issuer and CA subject match */
rv = X509_NAME_cmp(x509crl->crl->issuer, x509CAcert->cert_info->subject);
if (rv != 0) {
err = X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
break;
}
#endif
/* Check signature */
pubkey = (EVP_PKEY *) certParsePublicKey(x509CAcert);
if (!pubkey) {
err = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
break;
}
/* Check signature */
if ((rv = X509_CRL_verify(x509crl, pubkey) < 1)) {
err = X509_V_ERR_CRL_SIGNATURE_FAILURE;
break;
}
/* Check CRL validity */
if ((rv = X509_cmp_current_time(X509_CRL_get_nextUpdate(x509crl))) < 0) {
err = X509_V_ERR_CRL_HAS_EXPIRED;
break;
}
/* Check whether the serial number is among the revoked */
if (certIsRevoked(serialNumber, x509crl->crl) != 0) {
err = X509_V_ERR_CERT_REVOKED;
break;
}
serialNumber = X509_get_serialNumber(x509CAcert);
i++;
currCAcert = CAcerts[i];
if (!currCAcert) {
break;
}
x509crl = (X509_CRL *) currCAcert->crl;
x509CAcert = (X509 *) currCAcert->cert;
}
}
EVP_cleanup();
return err;
}
const char *certError(unsigned long error)
{
static char buf[1024];
/* FIXME */
ERR_load_ERR_strings();
ERR_load_crypto_strings();
snprintf(buf, 1024, "%s", ERR_error_string(error, NULL));
ERR_free_strings();
return (char *) &buf[0];
}
#endif

View File

@ -1,79 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2001, 2002
* Anna Erika Suortti <asuortti@cc.hut.fi>
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __cert_support_h__
#define __cert_support_h__
#include <openssl/x509.h>
#ifdef __cplusplus
extern "C" {
#endif
#define DIGITAL_SIGNATURE 0
#define NONREPUDIATION 1
#define KEY_ENCIPHERMENT 2
#define DATA_ENCIPHERMENT 3
#define KEY_AGREEMENT 4
#define CERTIFICATE_SIGN 5
#define CRL_SIGN 6
#define ENCIPHER_ONLY 7
#define DECIPHER_ONLY 8
typedef struct _scCertificate {
unsigned char *buf, *crlbuf;
unsigned long len, crllen;
X509 *cert;
X509_CRL *crl;
EVP_PKEY *pubkey;
} scCertificate;
extern scCertificate *certAlloc(void);
extern void certFree(scCertificate * cert);
extern void certFreeAll(scCertificate ** cert);
extern X509 *certParseCertificate(unsigned char *certbuf, unsigned int certlen);
extern void certFreeCertificate(X509 * cert);
extern X509_CRL *certParseCRL(unsigned char *crlbuf, unsigned int crllen);
extern void certFreeCRL(X509_CRL * crl);
extern EVP_PKEY *certParsePublicKey(X509 * cert);
extern void certFreePublicKey(EVP_PKEY * pubkey);
extern int certCheckValidity(X509 * cert);
extern int certCheckKeyUsage(X509 * cert, unsigned int bit);
extern int certIsSelfSigned(X509 * cert);
extern char *certGetIssuer(X509 * cert);
extern char *certParseDN(char *entry, char *field);
extern char *certGetSubject(X509 * cert);
extern char *certGetCRLDistributionPoint(X509 * cert);
extern int certVerifyCAChain(scCertificate ** x509CAcerts, X509 * cert);
extern const char *certError(unsigned long error);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,460 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(HAVE_OPENSSL)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <pwd.h>
#include <sys/stat.h>
#include <openssl/x509.h>
#include <openssl/rsa.h>
#include <openssl/rand.h>
#include <openssl/pem.h>
#include <opensc/opensc.h>
#include <opensc/pkcs15.h>
#include <opensc/scrandom.h>
#include "scam.h"
static const char *eid_path = ".eid";
static const char *auth_cert_file = "authorized_certificates";
typedef struct _scam_method_data {
sc_context_t *ctx;
sc_card_t *card;
struct sc_pkcs15_card *p15card;
int card_locked;
struct sc_pkcs15_object *objs[32];
struct sc_pkcs15_cert_info *cinfo;
struct sc_pkcs15_object *prkey, *pin;
} scam_method_data;
const char *p15_eid_usage(void)
{
static char buf[500];
memset(buf, 0, 500);
snprintf(buf, 500,
" -r <reader> Reader name\n"
);
return &buf[0];
}
/*
* Select a card reader
*/
static sc_reader_t *
p15_eid_select_reader(scam_context *sctx, const char *name)
{
sc_context_t *ctx = ((scam_method_data *) sctx->method_data)->ctx;
sc_reader_t *reader;
int i;
if (name) {
int name_len = strlen(name);
for (i = 0; i < ctx->reader_count; i++) {
reader = ctx->reader[i];
if (name_len <= strlen(reader->name)
&& !strncmp(name, reader->name, name_len))
return reader;
}
scam_print_msg(sctx,
"Card Reader \"%s\" not present\n",
name);
return NULL;
}
for (i = 0; i < ctx->reader_count; i++) {
reader = ctx->reader[i];
if (sc_detect_card_presence(reader, 0) & SC_SLOT_CARD_PRESENT)
return reader;
}
scam_print_msg(sctx, "No smart card present\n");
return NULL;
}
int p15_eid_init(scam_context * sctx, int argc, const char **argv)
{
scam_method_data *data = NULL;
const char *reader_name = NULL;
sc_reader_t *reader;
int r, i;
if (sctx->method_data) {
return SCAM_FAILED;
}
sctx->method_data = (scam_method_data *) malloc(sizeof(scam_method_data));
if (!sctx->method_data) {
return SCAM_FAILED;
}
memset(sctx->method_data, 0, sizeof(scam_method_data));
data = (scam_method_data *) sctx->method_data;
r = sc_establish_context(&data->ctx, "scam");
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_establish_context: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
for (i = 0; i < argc; i++) {
if (argv[i][0] == '-') {
char *optarg = (char *) argv[i + 1];
if (!optarg)
continue;
switch (argv[i][1]) {
case 'r':
reader_name = optarg;
break;
}
}
}
/* Select a card reader */
if (!(reader = p15_eid_select_reader(sctx, reader_name)))
return SCAM_FAILED;
scam_print_msg(sctx, "Using card reader %s\n", reader->name);
if ((r = sc_connect_card(reader, 0, &data->card)) != SC_SUCCESS) {
scam_print_msg(sctx, "sc_connect_card: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
sc_lock(data->card);
data->card_locked = 1;
r = sc_pkcs15_bind(data->card, &data->p15card);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_bind: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
r = sc_pkcs15_get_objects(data->p15card, SC_PKCS15_TYPE_CERT_X509, data->objs, 32);
if (r < 0) {
scam_print_msg(sctx, "sc_pkcs15_get_objects: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
if (r == 0) /* No certificates found */
return SCAM_FAILED;
/* FIXME: Add support for selecting certificate by ID */
data->cinfo = (struct sc_pkcs15_cert_info *) data->objs[0]->data;
r = sc_pkcs15_find_prkey_by_id_usage(data->p15card,
&data->cinfo->id,
SC_PKCS15_PRKEY_USAGE_SIGN,
&data->prkey);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_find_prkey_by_id_usage: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
r = sc_pkcs15_find_pin_by_auth_id(data->p15card, &data->prkey->auth_id, &data->pin);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_find_pin_by_auth_id: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
return SCAM_SUCCESS;
}
const char *p15_eid_pinentry(scam_context * sctx)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
struct sc_pkcs15_pin_info *pininfo = NULL;
static char buf[64];
if (!sctx->method_data) {
return NULL;
}
pininfo = (struct sc_pkcs15_pin_info *) data->pin->data;
snprintf(buf, 64, "Enter PIN%d [%s]: ", pininfo->reference, data->pin->label);
return buf;
}
int p15_eid_qualify(scam_context * sctx, unsigned char *password)
{
if (!sctx->method_data) {
return SCAM_FAILED;
}
if (!password)
return SCAM_FAILED;
/* FIXME */
#if 0
if (scQualifyPin(password) < 0)
return SCAM_FAILED;
#endif
return SCAM_SUCCESS;
}
static int format_eid_dir_path(const char *user, char **buf, uid_t *uid)
{
struct passwd *pwent = getpwnam(user);
char *dir = NULL;
if (!pwent)
return SCAM_FAILED;
dir = (char *) malloc(strlen(pwent->pw_dir) + strlen(eid_path) + 2);
if (!dir)
return SCAM_FAILED;
strcpy(dir, pwent->pw_dir);
strcat(dir, "/");
strcat(dir, eid_path);
*buf = dir;
if (uid)
*uid = pwent->pw_uid;
return SCAM_SUCCESS;
}
static int is_eid_dir_present(const char *user)
{
char *eid_dir = NULL;
struct stat stbuf;
int r;
uid_t uid;
r = format_eid_dir_path(user, &eid_dir, &uid);
if (r != SCAM_SUCCESS)
return r;
r = lstat(eid_dir, &stbuf);
/* Check if it is a real directory (no symlinks allowd),
owned by myself and if group/world-writable */
free(eid_dir);
if (r || !S_ISDIR(stbuf.st_mode) || (stbuf.st_uid != uid) ||
(stbuf.st_mode&(S_IWGRP|S_IWOTH)))
return SCAM_FAILED; /* lstat() or security checks failed */
return SCAM_SUCCESS;
}
static int get_certificate(const char *user, int idx, X509 ** cert_out)
{
char *dir = NULL, *cert_path = NULL;
int i, r;
BIO *in = NULL;
X509 *cert = NULL;
int err = SCAM_FAILED;
r = format_eid_dir_path(user, &dir, NULL);
if (r != SCAM_SUCCESS)
return r;
cert_path = (char *) malloc(strlen(dir) + strlen(auth_cert_file) + 2);
if (!cert_path) {
goto end;
}
strcpy(cert_path, dir);
strcat(cert_path, "/");
strcat(cert_path, auth_cert_file);
in = BIO_new(BIO_s_file());
if (!in) {
goto end;
}
if (BIO_read_filename(in, cert_path) <= 0) {
goto end;
}
for (i = 0; i < idx; i++) {
if (cert)
X509_free(cert);
cert = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
if (!cert)
goto end;
}
*cert_out = cert;
err = SCAM_SUCCESS;
end:
if (in)
BIO_free(in);
if (dir)
free(dir);
if (cert_path)
free(cert_path);
return err;
}
#define MSGTYPE_NONE 0
#define MSGTYPE_PRINT 1
#define MSGTYPE_LOG 2
int p15_eid_auth(scam_context * sctx, int argc, const char **argv,
const char *user, const char *password)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
u8 random_data[20], chg[256];
char last_msg[256];
int r, err = SCAM_FAILED, chglen, certidx;
int last_msgtype;
EVP_PKEY *pubkey = NULL;
X509 *cert = NULL;
if (!sctx->method_data) {
return SCAM_FAILED;
}
r = is_eid_dir_present(user);
if (r != SCAM_SUCCESS) {
scam_print_msg(sctx, "No such user, .eid dir unreadable, nonexistent or unsafe.\n");
return SCAM_FAILED;
}
/* Loop over all certificates in the user's certificate file */
last_msgtype = MSGTYPE_NONE;
certidx = 0;
while (1) {
certidx++;
if (pubkey)
EVP_PKEY_free(pubkey);
if (cert)
X509_free(cert);
cert = NULL;
pubkey = NULL;
r = get_certificate(user, certidx, &cert);
if (r != SCAM_SUCCESS) {
if (certidx == 1) {
last_msgtype = MSGTYPE_PRINT;
snprintf(last_msg, sizeof(last_msg),
"get_certificate failed.\n");
}
switch (last_msgtype) {
case MSGTYPE_PRINT:
scam_print_msg(sctx, last_msg);
case MSGTYPE_LOG:
scam_log_msg(sctx, last_msg);
break;
}
break;
}
pubkey = X509_get_pubkey(cert);
if (!pubkey || pubkey->type != EVP_PKEY_RSA) {
last_msgtype = MSGTYPE_LOG;
snprintf(last_msg, sizeof(last_msg),
"Invalid public key. (user %s)\n", user);
continue;
}
chglen = RSA_size(pubkey->pkey.rsa);
if (chglen > sizeof(chg)) {
last_msgtype = MSGTYPE_PRINT;
snprintf(last_msg, sizeof(last_msg),
"RSA key too big.\n");
continue;
}
r = scrandom_get_data(random_data, sizeof(random_data));
if (r < 0) {
last_msgtype = MSGTYPE_LOG;
snprintf(last_msg, sizeof(last_msg),
"scrandom_get_data failed.\n");
continue;
}
RAND_seed(random_data, sizeof(random_data));
r = sc_pkcs15_verify_pin(data->p15card,
(struct sc_pkcs15_pin_info *) data->pin->data,
(const u8 *) password, strlen(password));
if (r != SC_SUCCESS) {
last_msgtype = MSGTYPE_PRINT;
snprintf(last_msg, sizeof(last_msg),
"sc_pkcs15_verify_pin: %s\n", sc_strerror(r));
continue;
}
/* We currently assume that all cards are capable of signing
* a SHA1 digest - that's a much safer bet than going for
* raw RSA.
* The best solution would be to look at the list of supported
* algorithms and pick an appropriate hash.
*
* Note the hash algorithm must match the first argument in the
* call to RSA_verify below
*/
r = sc_pkcs15_compute_signature(data->p15card, data->prkey,
SC_ALGORITHM_RSA_PAD_PKCS1
| SC_ALGORITHM_RSA_HASH_SHA1,
random_data, 20, chg, chglen);
if (r < 0) {
last_msgtype = MSGTYPE_PRINT;
snprintf(last_msg, sizeof(last_msg),
"sc_pkcs15_compute_signature: %s\n",
sc_strerror(r));
continue;
}
r = RSA_verify(NID_sha1, random_data, 20, chg, chglen,
pubkey->pkey.rsa);
if (r != 1) {
last_msgtype = MSGTYPE_PRINT;
snprintf(last_msg, sizeof(last_msg),
"Signature verification failed.\n");
continue;
}
err = SCAM_SUCCESS;
break;
}
if (pubkey)
EVP_PKEY_free(pubkey);
if (cert)
X509_free(cert);
return err;
}
#undef MSGTYPE_NONE
#undef MSGTYPE_PRINT
#undef MSGTYPE_LOG
void p15_eid_deinit(scam_context * sctx)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
if (!sctx->method_data) {
return;
}
if (data->card_locked) {
sc_unlock(data->card);
}
data->card_locked = 0;
if (data->p15card) {
sc_pkcs15_unbind(data->p15card);
}
data->p15card = NULL;
if (data->card) {
sc_disconnect_card(data->card, 0);
}
data->card = NULL;
if (data->ctx) {
sc_release_context(data->ctx);
}
data->ctx = NULL;
free(sctx->method_data);
sctx->method_data = NULL;
}
struct scam_framework_ops scam_fw_p15_eid =
{
"pkcs15-eid", /* name */
p15_eid_usage, /* usage */
p15_eid_init, /* init */
p15_eid_pinentry, /* pinentry */
p15_eid_qualify, /* qualify */
p15_eid_auth, /* auth */
p15_eid_deinit, /* deinit */
NULL, /* open_session */
NULL /* close_session */
};
#endif

View File

@ -1,530 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(HAVE_OPENSSL) && defined(HAVE_LDAP)
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <openssl/x509.h>
#include <openssl/rsa.h>
#include <openssl/rand.h>
#include <opensc/opensc.h>
#include <opensc/pkcs15.h>
#include <opensc/scldap.h>
#include <opensc/scrandom.h>
#include <opensc/log.h>
#include "cert_support.h"
#include "scam.h"
typedef struct _scam_method_data {
sc_context_t *ctx;
sc_card_t *card;
struct sc_pkcs15_card *p15card;
int card_locked;
struct sc_pkcs15_object *objs[32];
struct sc_pkcs15_cert_info *cinfo;
struct sc_pkcs15_object *prkey, *pin;
scldap_context *lctx;
char *scldap_entry;
} scam_method_data;
#define MAX_PATHLEN 10
#define MAX_ENTRYLEN 256
const char *p15_ldap_usage(void)
{
static char buf[500];
memset(buf, 0, 500);
snprintf(buf, 500,
" -r <reader> Reader name\n"
"LDAP specific options:\n%s", scldap_show_arguments()
);
return &buf[0];
}
/*
* Select a card reader
*/
static sc_reader_t *
p15_eid_select_reader(scam_context *sctx, const char *name)
{
sc_context_t *ctx = ((scam_method_data *) sctx->method_data)->ctx;
sc_reader_t *reader;
int i;
if (name) {
int name_len = strlen(name);
for (i = 0; i < ctx->reader_count; i++) {
reader = ctx->reader[i];
if (name_len <= strlen(reader->name)
&& !strncmp(name, reader->name, name_len))
return reader;
}
scam_print_msg(sctx,
"Card Reader \"%s\" not present\n",
name);
return NULL;
}
for (i = 0; i < ctx->reader_count; i++) {
reader = ctx->reader[i];
if (sc_detect_card_presence(reader, 0) & SC_SLOT_CARD_PRESENT)
return reader;
}
scam_print_msg(sctx, "No smart card present\n");
return NULL;
}
int p15_ldap_init(scam_context * sctx, int argc, const char **argv)
{
scam_method_data *data = NULL;
const char *reader_name = NULL;
sc_reader_t *reader;
int r, i;
if (sctx->method_data) {
return SCAM_FAILED;
}
sctx->method_data = (scam_method_data *) malloc(sizeof(scam_method_data));
if (!sctx->method_data) {
return SCAM_FAILED;
}
memset(sctx->method_data, 0, sizeof(scam_method_data));
data = (scam_method_data *) sctx->method_data;
r = sc_establish_context(&data->ctx, "scam");
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_establish_context: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
for (i = 0; i < argc; i++) {
if (argv[i][0] == '-') {
char *optarg = (char *) argv[i + 1];
if (!optarg)
continue;
switch (argv[i][1]) {
case 'r':
reader_name = optarg;
break;
}
}
}
/* Select a card reader */
if (!(reader = p15_eid_select_reader(sctx, reader_name)))
return SCAM_FAILED;
scam_print_msg(sctx, "Using card reader %s\n", reader->name);
if ((r = sc_connect_card(reader, 0, &data->card)) != SC_SUCCESS) {
scam_print_msg(sctx, "sc_connect_card: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
sc_lock(data->card);
data->card_locked = 1;
r = sc_pkcs15_bind(data->card, &data->p15card);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_bind: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
r = sc_pkcs15_get_objects(data->p15card, SC_PKCS15_TYPE_CERT_X509, data->objs, 32);
if (r < 0) {
scam_print_msg(sctx, "sc_pkcs15_get_objects: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
if (r == 0) /* No certificates found */
return SCAM_FAILED;
/* FIXME: Add support for selecting certificate by ID */
data->cinfo = (struct sc_pkcs15_cert_info *) data->objs[0]->data;
r = sc_pkcs15_find_prkey_by_id_usage(data->p15card,
&data->cinfo->id,
SC_PKCS15_PRKEY_USAGE_SIGN,
&data->prkey);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_find_prkey_by_id_usage: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
r = sc_pkcs15_find_pin_by_auth_id(data->p15card, &data->prkey->auth_id, &data->pin);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_find_pin_by_auth_id: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
data->lctx = scldap_parse_parameters(SCLDAP_CONF_PATH);
if (!data->lctx) {
return SCAM_FAILED;
}
scldap_parse_arguments(&data->lctx, argc, argv);
data->scldap_entry = (char *) malloc(MAX_ENTRYLEN);
if (!data->scldap_entry) {
return SCAM_FAILED;
}
memset(data->scldap_entry, 0, MAX_ENTRYLEN);
return SCAM_SUCCESS;
}
const char *p15_ldap_pinentry(scam_context * sctx)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
struct sc_pkcs15_pin_info *pininfo = NULL;
static char buf[64];
if (!sctx->method_data) {
return NULL;
}
pininfo = (struct sc_pkcs15_pin_info *) data->pin->data;
snprintf(buf, 64, "Enter PIN%d [%s]: ", pininfo->reference, data->pin->label);
return buf;
}
int p15_ldap_qualify(scam_context * sctx, unsigned char *password)
{
if (!sctx->method_data) {
return SCAM_FAILED;
}
if (!password)
return SCAM_FAILED;
/* FIXME */
#if 0
if (scQualifyPin(password) < 0)
return SCAM_FAILED;
#endif
return SCAM_SUCCESS;
}
static int copy_result(scldap_result * lresult, unsigned char **result, unsigned long *resultlen)
{
if (!lresult)
return -1;
*result = NULL;
*resultlen = 0;
*result = (unsigned char *) malloc(lresult->result[0].datalen + 1);
if (!*result)
return -1;
memset(*result, 0, lresult->result[0].datalen + 1);
memcpy(*result, lresult->result[0].data, lresult->result[0].datalen);
*resultlen = lresult->result[0].datalen;
return 0;
}
static void modify_base(scam_context * sctx, const char *entry, char *dn)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
char approx_entry[MAX_ENTRYLEN];
int entrynum = -1;
if (!sctx || !entry || !dn)
return;
entrynum = scldap_get_entry(data->lctx, entry);
if (entrynum < 0) {
return;
}
snprintf(approx_entry, MAX_ENTRYLEN, "%s %s approx base", data->p15card->label, data->p15card->manufacturer_id);
if (scldap_approx_base_by_dn(data->lctx, approx_entry, dn, &data->lctx->entry[entrynum].base) < 0) {
return;
}
sc_debug(data->ctx, "modify_base: %s\n", data->lctx->entry[entrynum].base);
}
int p15_ldap_auth(scam_context * sctx, int argc, const char **argv,
const char *user, const char *password)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
struct sc_pkcs15_cert *p15cert = NULL;
scCertificate *CardCert = NULL, *Cert = NULL, *CACerts[MAX_PATHLEN];
X509 *currcert = NULL;
u8 random_data[20], chg[256];
scldap_result *lresult = NULL;
int r = 0, i = 0, err = SCAM_FAILED, chglen;
char *dn;
if (!sctx->method_data) {
return SCAM_FAILED;
}
for (i = 0; i < MAX_PATHLEN; i++) {
CACerts[i] = NULL;
}
Cert = certAlloc();
if (!Cert) {
goto end;
}
CardCert = certAlloc();
if (!CardCert) {
goto end;
}
r = sc_pkcs15_read_certificate(data->p15card, data->cinfo, &p15cert);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_read_certificate: %s\n", sc_strerror(r));
goto end;
}
/* FIXME */
CardCert->len = p15cert->data_len;
CardCert->buf = (unsigned char *) malloc(CardCert->len);
if (!CardCert->buf) {
scam_print_msg(sctx, "out of memory\n", sc_strerror(r));
goto end;
}
memcpy(CardCert->buf, p15cert->data, p15cert->data_len);
/* Parse user certificate just once into a x509 structure
and not for each individual operation */
if (!(CardCert->cert = certParseCertificate(CardCert->buf, CardCert->len))) {
scam_print_msg(sctx, "certParseCertificate failed: invalid certificate.\n");
goto end;
}
snprintf(data->scldap_entry, MAX_ENTRYLEN, "%s %s auth certificate", data->p15card->label, data->p15card->manufacturer_id);
dn = certGetSubject(CardCert->cert);
modify_base(sctx, data->scldap_entry, dn);
free(dn);
r = scldap_search(data->lctx, data->scldap_entry, &lresult, 1, user);
if ((r < 0) || (copy_result(lresult, &Cert->buf, &Cert->len) < 0)) {
scam_print_msg(sctx, "Search failed: no auth certificate found.\n");
goto end;
}
scldap_free_result(lresult);
lresult = NULL;
if (memcmp(CardCert->buf, Cert->buf, Cert->len) != 0) {
scam_print_msg(sctx, "Certificate comparing failed.\n");
goto end;
}
certFree(CardCert);
CardCert = NULL;
/* Parse user certificate just once into a x509 structure
and not for each individual operation */
if (!(Cert->cert = certParseCertificate(Cert->buf, Cert->len))) {
scam_print_msg(sctx, "certParseCertificate failed: invalid certificate.\n");
goto end;
}
/* Do not accept self signed user certificates or certificates
without issuer or subject fields */
if (certIsSelfSigned(Cert->cert) != 0) {
scam_print_msg(sctx, "certIsSelfSigned failed: certificate is not signed by a CA.\n");
goto end;
}
/* We want an encipherment key */
if ((r = certCheckKeyUsage(Cert->cert, DATA_ENCIPHERMENT)) < 1) {
scam_print_msg(sctx, "certCheckKeyUsage failed: certificate cannot be used for encipherment.\n");
if (r == -1) {
scam_log_msg(sctx, "KeyUsage check failed (user %s).\n", user);
} else {
scam_log_msg(sctx, "Wrong certificate type (user %s).\n", user);
}
goto end;
}
if (!(Cert->pubkey = certParsePublicKey(Cert->cert))) {
scam_print_msg(sctx, "certParsePublicKey failed: invalid public key in certificate.\n");
scam_log_msg(sctx, "Invalid public key (user %s).\n", user);
goto end;
}
if (Cert->pubkey->type != EVP_PKEY_RSA) {
scam_log_msg(sctx, "Invalid public key. (user %s)\n", user);
goto end;
}
chglen = RSA_size(Cert->pubkey->pkey.rsa);
if (chglen > sizeof(chg)) {
scam_print_msg(sctx, "RSA key too big.\n");
goto end;
}
/* Parse issuer from each one certificate
in turn when you get them from the LDAP serer and stuff them
all into the chain when we have other certificates than FINEID
until issuer == subject. */
do {
char *distpoint = NULL;
/* Find empty slot */
for (i = 0; i < MAX_PATHLEN; i++) {
if (!(CACerts[i])) {
break;
}
}
/* Path length exceeded */
if (i == MAX_PATHLEN) {
goto end;
}
CACerts[i] = certAlloc();
if (!(CACerts[i])) {
goto end;
}
snprintf(data->scldap_entry, MAX_ENTRYLEN, "%s %s ca certificate", data->p15card->label, data->p15card->manufacturer_id);
modify_base(sctx, data->scldap_entry, certGetIssuer(Cert->cert));
r = scldap_search(data->lctx, data->scldap_entry, &lresult, 1, NULL);
if ((r < 0) || (copy_result(lresult, &CACerts[i]->buf, &CACerts[i]->len) < 0)) {
scam_print_msg(sctx, "Search failed: no CA certificate.\n");
goto end;
}
scldap_free_result(lresult);
lresult = NULL;
/* Parse CA certificate into a x509 structure */
if (!(CACerts[i]->cert = certParseCertificate(CACerts[i]->buf, CACerts[i]->len))) {
scam_print_msg(sctx, "certParseCertificate failed: invalid CA certificate.\n");
goto end;
}
distpoint = certGetCRLDistributionPoint(Cert->cert);
snprintf(data->scldap_entry, MAX_ENTRYLEN, "%s %s crl", data->p15card->label, data->p15card->manufacturer_id);
if (scldap_is_valid_url(distpoint)) {
if (scldap_url_to_entry(data->lctx, data->scldap_entry, distpoint) < 0) {
scam_print_msg(sctx, "scldap_url_to_entry failed: invalid CRL.\n");
free(distpoint);
distpoint = NULL;
goto end;
}
}
free(distpoint);
distpoint = NULL;
r = scldap_search(data->lctx, data->scldap_entry, &lresult, 1, NULL);
if ((r < 0) || (copy_result(lresult, &CACerts[i]->crlbuf, &CACerts[i]->crllen) < 0)) {
scam_print_msg(sctx, "Search failed: CRL not found.\n");
goto end;
}
scldap_free_result(lresult);
lresult = NULL;
if (!(CACerts[i]->crl = certParseCRL(CACerts[i]->crlbuf, CACerts[i]->crllen))) {
scam_print_msg(sctx, "certParseCRL failed: invalid CRL.\n");
scam_log_msg(sctx, "Could not parse CA CRL.\n");
goto end;
}
currcert = CACerts[i]->cert;
} while (!certIsSelfSigned(currcert));
if ((r = certVerifyCAChain(CACerts, Cert->cert)) != 0) {
scam_print_msg(sctx, "certVerifyCAChain failed: certificate has invalid information.\n");
scam_log_msg(sctx, "certVerifyCAChain failed: %s.\n", certError((unsigned long) r));
goto end;
}
certFreeAll(CACerts);
r = scrandom_get_data(random_data, sizeof(random_data));
if (r < 0) {
scam_log_msg(sctx, "scrandom_get_data failed.\n");
goto end;
}
RAND_seed(random_data, sizeof(random_data));
r = sc_pkcs15_verify_pin(data->p15card, (struct sc_pkcs15_pin_info *) data->pin->data, (const u8 *) password, strlen(password));
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_verify_pin: %s\n", sc_strerror(r));
goto end;
}
/* We currently assume that all cards are capable of signing
* a SHA1 digest - that's a much safer bet than going for
* raw RSA.
* The best solution would be to look at the list of supported
* algorithms and pick an appropriate hash.
*
* Note the hash algorithm must match the first argument in the
* call to RSA_verify below
*/
r = sc_pkcs15_compute_signature(data->p15card, data->prkey,
SC_ALGORITHM_RSA_PAD_PKCS1
| SC_ALGORITHM_RSA_HASH_SHA1,
random_data, 20, chg, chglen);
if (r < 0) {
scam_print_msg(sctx, "sc_pkcs15_compute_signature: %s\n", sc_strerror(r));
goto end;
}
r = RSA_verify(NID_sha1, random_data, 20, chg, chglen, Cert->pubkey->pkey.rsa);
if (r != 1) {
scam_print_msg(sctx, "Signature verification failed.\n");
goto end;
}
err = SCAM_SUCCESS;
end:
if (CardCert)
certFree(CardCert);
if (Cert)
certFree(Cert);
certFreeAll(CACerts);
if (p15cert)
sc_pkcs15_free_certificate(p15cert);
return err;
}
void p15_ldap_deinit(scam_context * sctx)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
if (!sctx->method_data) {
return;
}
if (data->scldap_entry) {
free(data->scldap_entry);
}
data->scldap_entry = NULL;
if (data->lctx) {
scldap_free_parameters(data->lctx);
}
data->lctx = NULL;
if (data->card_locked) {
sc_unlock(data->card);
}
data->card_locked = 0;
if (data->p15card) {
sc_pkcs15_unbind(data->p15card);
}
data->p15card = NULL;
if (data->card) {
sc_disconnect_card(data->card, 0);
}
data->card = NULL;
if (data->ctx) {
sc_release_context(data->ctx);
}
data->ctx = NULL;
free(sctx->method_data);
sctx->method_data = NULL;
}
struct scam_framework_ops scam_fw_p15_ldap =
{
"pkcs15-ldap", /* name */
p15_ldap_usage, /* usage */
p15_ldap_init, /* init */
p15_ldap_pinentry, /* pinentry */
p15_ldap_qualify, /* qualify */
p15_ldap_auth, /* auth */
p15_ldap_deinit, /* deinit */
NULL, /* open_session */
NULL /* close_session */
};
#endif

View File

@ -1,219 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "scam.h"
#define DIM(v) (sizeof(v)/(sizeof((v)[0])))
struct scam_framework_ops *scam_frameworks[] =
{
#ifdef HAVE_OPENSSL
&scam_fw_p15_eid,
#ifdef HAVE_LDAP
&scam_fw_p15_ldap,
#endif
#endif
NULL
};
int scam_enum_modules(void)
{
int count = DIM(scam_frameworks) - 1;
return (!count ? -1 : count);
}
void scam_parse_parameters(scam_context * sctx, int argc, const char **argv)
{
const char *auth_method = "auth_method=";
if (!sctx)
return;
while (argc-- > 0) {
if (!strncmp(*argv, auth_method, strlen(auth_method))) {
const char *p = *argv + strlen(auth_method);
size_t len = strlen(p) + 1;
sctx->auth_method = (char *) realloc(sctx->auth_method, len);
if (!sctx->auth_method)
break;
memset(sctx->auth_method, 0, len);
strncpy(sctx->auth_method, p, len - 1);
}
++argv;
}
}
int scam_select_by_name(const char *method)
{
int i;
if (!method)
return -1;
for (i = 0; scam_frameworks[i]; i++) {
if (!strcmp(scam_frameworks[i]->name, method)) {
return i;
break;
}
}
return -1;
}
void scam_print_msg(scam_context * sctx, char *str,...)
{
va_list ap;
char buf[128];
va_start(ap, str);
memset(buf, 0, 128);
vsnprintf(buf, 128, str, ap);
va_end(ap);
if (sctx && sctx->printmsg)
sctx->printmsg(sctx, buf);
}
void scam_log_msg(scam_context * sctx, char *str,...)
{
va_list ap;
char buf[1024];
va_start(ap, str);
memset(buf, 0, 1024);
vsnprintf(buf, 1024, str, ap);
va_end(ap);
if (sctx && sctx->logmsg)
sctx->logmsg(sctx, buf);
}
const char *scam_name(scam_context * sctx)
{
if (!sctx)
return NULL;
if (sctx->method >= scam_enum_modules())
return NULL;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->name) {
return scam_frameworks[sctx->method]->name;
}
return NULL;
}
const char *scam_usage(scam_context * sctx)
{
if (!sctx)
return NULL;
if (sctx->method >= scam_enum_modules())
return NULL;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->usage) {
return scam_frameworks[sctx->method]->usage();
}
return NULL;
}
int scam_init(scam_context * sctx, int argc, const char **argv)
{
if (!sctx)
return SCAM_FAILED;
if (sctx->method >= scam_enum_modules())
return SCAM_FAILED;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->init) {
return scam_frameworks[sctx->method]->init(sctx, argc, argv);
}
return SCAM_SUCCESS;
}
const char *scam_pinentry(scam_context * sctx)
{
if (!sctx)
return NULL;
if (sctx->method >= scam_enum_modules())
return NULL;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->pinentry) {
return scam_frameworks[sctx->method]->pinentry(sctx);
}
return NULL;
}
int scam_qualify(scam_context * sctx, unsigned char *password)
{
if (!sctx)
return SCAM_FAILED;
if (sctx->method >= scam_enum_modules())
return SCAM_FAILED;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->qualify) {
return scam_frameworks[sctx->method]->qualify(sctx, password);
}
return SCAM_SUCCESS;
}
int scam_auth(scam_context * sctx, int argc, const char **argv, const char *user, const char *password)
{
if (!sctx)
return SCAM_FAILED;
if (sctx->method >= scam_enum_modules())
return SCAM_FAILED;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->auth) {
return scam_frameworks[sctx->method]->auth(sctx, argc, argv, user, password);
}
return SCAM_FAILED;
}
void scam_deinit(scam_context * sctx)
{
if (!sctx)
return;
if (sctx->method >= scam_enum_modules())
return;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->deinit) {
scam_frameworks[sctx->method]->deinit(sctx);
}
}
int scam_open_session(scam_context * sctx, int argc, const char **argv, const char *user)
{
if (!sctx)
return SCAM_FAILED;
if (sctx->method >= scam_enum_modules())
return SCAM_FAILED;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->open_session) {
return scam_frameworks[sctx->method]->open_session(sctx, argc, argv, user);
}
return SCAM_SUCCESS;
}
int scam_close_session(scam_context * sctx, int argc, const char **argv, const char *user)
{
if (!sctx)
return SCAM_FAILED;
if (sctx->method >= scam_enum_modules())
return SCAM_FAILED;
if (scam_frameworks[sctx->method] && scam_frameworks[sctx->method]->close_session) {
return scam_frameworks[sctx->method]->close_session(sctx, argc, argv, user);
}
return SCAM_SUCCESS;
}

View File

@ -1,98 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SCAM_H
#define _SCAM_H
#ifdef __cplusplus
extern "C" {
#endif
#define SCAM_FAILED 1
#define SCAM_SUCCESS 0
typedef struct _scam_context scam_context;
struct _scam_context {
int method;
char *auth_method;
/* Print message to screen, internally used by scam_print_msg */
void (*printmsg) (scam_context * sctx, char *str);
/* Log message to syslog, specific log file, etc */
/* Internally used by scam_log_msg */
void (*logmsg) (scam_context * sctx, char *str);
/* Used by printmsg/logmsg */
void *msg_data;
/* Private data for scam_framework_ops internals */
void *method_data;
};
/*
* Framework abstraction for smart card authentication
*/
struct scam_framework_ops {
/* Framework name */
const char *name;
/* Return a string for help messages, list known parameters, etc. */
const char *(*usage) (void);
/* Establish a connection to the resource manager, etc. */
int (*init) (scam_context * sctx, int argc, const char **argv);
/* Return a pin entry string for conversation functions */
const char *(*pinentry) (scam_context * sctx);
/* Qualify password - is the password actually a PIN or not */
/* Speeds up the authentication process with normal passwords */
int (*qualify) (scam_context * sctx, unsigned char *password);
/* Authentication function */
int (*auth) (scam_context * sctx, int argc, const char **argv, const char *user, const char *password);
/* Close established connections, free memory, etc. */
void (*deinit) (scam_context * sctx);
/* Open session after authentication */
int (*open_session) (scam_context * sctx, int argc, const char **argv, const char *user);
/* Close session */
int (*close_session) (scam_context * sctx, int argc, const char **argv, const char *user);
};
extern struct scam_framework_ops scam_fw_p15_eid;
extern struct scam_framework_ops scam_fw_p15_ldap;
extern struct scam_framework_ops *scam_frameworks[];
extern int scam_enum_modules(void);
extern void scam_parse_parameters(scam_context * sctx, int argc, const char **argv);
extern int scam_select_by_name(const char *method);
extern void scam_print_msg(scam_context * sctx, char *str,...);
extern void scam_log_msg(scam_context * sctx, char *str,...);
extern const char *scam_name(scam_context * sctx);
extern const char *scam_usage(scam_context * sctx);
extern int scam_init(scam_context * sctx, int argc, const char **argv);
extern const char *scam_pinentry(scam_context * sctx);
extern int scam_qualify(scam_context * sctx, unsigned char *password);
extern int scam_auth(scam_context * sctx, int argc, const char **argv, const char *user, const char *password);
extern void scam_deinit(scam_context * sctx);
extern int scam_open_session(scam_context * sctx, int argc, const char **argv, const char *user);
extern int scam_close_session(scam_context * sctx, int argc, const char **argv, const char *user);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,20 +0,0 @@
# Process this file with automake to create Makefile.in
includedir = @includedir@/opensc
MAINTAINERCLEANFILES = Makefile.in
include_HEADERS = scldap.h
if HAVE_LDAP
lib_LTLIBRARIES = libscldap.la
noinst_PROGRAMS = test-ldap
endif
libscldap_la_SOURCES = scldap.c scldap.h
libscldap_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@
libscldap_la_LIBADD = @LIBSCCONF@ @LIBLDAP@
test_ldap_SOURCES = test-ldap.c
test_ldap_LDFLAGS = @LDFLAGS@
test_ldap_LDADD = libscldap.la

View File

@ -1,931 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2001, 2002
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef HAVE_LBER_H
#include <lber.h>
#endif
#ifdef HAVE_LDAP_H
#include <ldap.h>
#endif
#ifdef HAVE_LDAP_SSL_H
#include <ldap_ssl.h>
#endif
#include "scldap.h"
extern char **environ;
typedef struct _cb_data {
scldap_context *ctx;
char *cardprefix;
} cb_data;
static int attrs_cb(scconf_context * config, const scconf_block * block, scconf_entry * entry, int depth)
{
scldap_param_entry *lentry = (scldap_param_entry *) entry->arg;
const scconf_list *list = scconf_find_list(block, entry->name);
for (; list; list = list->next) {
if (lentry->numattrs >= SCLDAP_MAX_ATTRIBUTES) {
break;
}
lentry->attributes = (char **) realloc(lentry->attributes, (lentry->numattrs + 2) * sizeof(char *));
if (!lentry->attributes)
return 1;
lentry->attributes[lentry->numattrs] = strdup(list->data);
lentry->numattrs++;
lentry->attributes[lentry->numattrs] = NULL;
}
return 0; /* 0 for ok, 1 for error */
}
static int ldap_cb(scconf_context * config, const scconf_block * block, scconf_entry * entry, int depth)
{
cb_data *trans = (cb_data *) entry->arg;
scldap_context *ctx = trans->ctx;
char *cardprefix = trans->cardprefix;
scldap_param_entry *lentry = (scldap_param_entry *) &ctx->entry[ctx->entries];
scconf_entry centry[] =
{
{"ldaphost", SCCONF_STRING, SCCONF_ALLOC, &lentry->ldaphost, NULL},
{"ldapport", SCCONF_INTEGER, SCCONF_ALLOC, &lentry->ldapport, NULL},
{"scope", SCCONF_INTEGER, SCCONF_ALLOC, &lentry->scope, NULL},
{"binddn", SCCONF_STRING, SCCONF_ALLOC, &lentry->binddn, NULL},
{"passwd", SCCONF_STRING, SCCONF_ALLOC, &lentry->passwd, NULL},
{"base", SCCONF_STRING, SCCONF_ALLOC, &lentry->base, NULL},
{"attributes", SCCONF_CALLBACK, 0, (void *) attrs_cb, lentry},
{"filter", SCCONF_STRING, SCCONF_ALLOC, &lentry->filter, NULL},
{NULL}
};
char *ldapsuffix = NULL;
size_t len = 0;
if (ctx->entries >= SCLDAP_MAX_ENTRIES)
return 0; /* Hard limit reached, just return OK */
ldapsuffix = scconf_list_strdup(block->name, " ");
if (!ldapsuffix) {
return 1;
}
if (cardprefix) {
len = strlen(cardprefix) + 1;
}
len += strlen(ldapsuffix) + 1;
lentry->entry = (char *) malloc(len);
if (!lentry->entry) {
free(ldapsuffix);
return 1;
}
memset(lentry->entry, 0, len);
snprintf(lentry->entry, len, "%s%s%s", cardprefix ? cardprefix : "", cardprefix ? " " : "", ldapsuffix);
free(ldapsuffix);
if (scconf_parse_entries(config, block, centry) != 0) {
return 1;
}
ctx->entries++;
ctx->entry = (scldap_param_entry *) realloc(ctx->entry, (ctx->entries + 2) * sizeof(scldap_param_entry));
if (!ctx->entry)
return 1;
memset(&ctx->entry[ctx->entries], 0, sizeof(scldap_param_entry));
return 0; /* 0 for ok, 1 for error */
}
static int card_cb(scconf_context * config, const scconf_block * block, scconf_entry * entry, int depth)
{
cb_data *trans = (cb_data *) entry->arg;
scconf_entry card_entry[] =
{
{"ldap", SCCONF_CALLBACK, SCCONF_ALL_BLOCKS, (void *) ldap_cb, trans},
{NULL}
};
trans->cardprefix = scconf_list_strdup(block->name, " ");
if (scconf_parse_entries(config, block, card_entry) != 0) {
free(trans->cardprefix);
trans->cardprefix = NULL;
return 1;
}
free(trans->cardprefix);
trans->cardprefix = NULL;
return 0; /* 0 for ok, 1 for error */
}
scldap_context *scldap_parse_parameters(const char *filename)
{
scldap_context *ctx = NULL;
ctx = (scldap_context *) malloc(sizeof(scldap_context));
if (!ctx) {
return NULL;
}
memset(ctx, 0, sizeof(scldap_context));
ctx->entry = (scldap_param_entry *) realloc(ctx->entry, (ctx->entries + 2) * sizeof(scldap_param_entry));
if (!ctx->entry) {
scldap_free_parameters(ctx);
return NULL;
}
memset(&ctx->entry[ctx->entries], 0, sizeof(scldap_param_entry));
if (filename) {
cb_data trans = {ctx, NULL};
scconf_entry entry[] =
{
{"ldap", SCCONF_CALLBACK, SCCONF_ALL_BLOCKS, (void *) ldap_cb, &trans},
{"card", SCCONF_CALLBACK, SCCONF_ALL_BLOCKS, (void *) card_cb, &trans},
{NULL}
};
ctx->conf = scconf_new(filename);
if (!ctx->conf) {
scldap_free_parameters(ctx);
return NULL;
}
if (scconf_parse(ctx->conf) < 1) {
scldap_free_parameters(ctx);
return NULL;
}
if (scconf_parse_entries(ctx->conf, NULL, entry) != 0) {
scldap_free_parameters(ctx);
return NULL;
}
}
ctx->entries++;
ctx->active = 0;
return ctx;
}
void scldap_show_parameters(scldap_context * ctx)
{
unsigned int i, j;
if (!ctx)
return;
for (i = 0; i < ctx->entries; i++) {
if (ctx->entry[i].entry)
printf("[%i]->entry=%s\n", i, ctx->entry[i].entry);
if (ctx->entry[i].ldaphost)
printf("[%i]->ldaphost=%s\n", i, ctx->entry[i].ldaphost);
printf("[%i]->ldapport=%i\n", i, ctx->entry[i].ldapport);
printf("[%i]->scope=%i\n", i, ctx->entry[i].scope);
if (ctx->entry[i].binddn)
printf("[%i]->binddn=%s\n", i, ctx->entry[i].binddn);
if (ctx->entry[i].passwd)
printf("[%i]->passwd=%s\n", i, ctx->entry[i].passwd);
if (ctx->entry[i].base)
printf("[%i]->base=%s\n", i, ctx->entry[i].base);
for (j = 0; j < ctx->entry[i].numattrs; j++) {
if (ctx->entry[i].attributes[j])
printf("[%i]->attribute[%i]=%s\n", i, j, ctx->entry[i].attributes[j]);
}
if (ctx->entry[i].filter)
printf("[%i]->filter=%s\n\n", i, ctx->entry[i].filter);
}
}
void scldap_free_parameters(scldap_context * ctx)
{
unsigned int i, j;
if (!ctx)
return;
if (ctx) {
for (i = 0; i < ctx->entries; i++) {
if (ctx->entry[i].entry) {
free(ctx->entry[i].entry);
}
ctx->entry[i].entry = NULL;
if (ctx->entry[i].ldaphost) {
free(ctx->entry[i].ldaphost);
}
ctx->entry[i].ldaphost = NULL;
ctx->entry[i].ldapport = 0;
ctx->entry[i].scope = 0;
if (ctx->entry[i].binddn) {
free(ctx->entry[i].binddn);
}
ctx->entry[i].binddn = NULL;
if (ctx->entry[i].passwd) {
free(ctx->entry[i].passwd);
}
ctx->entry[i].passwd = NULL;
if (ctx->entry[i].base) {
free(ctx->entry[i].base);
}
ctx->entry[i].base = NULL;
for (j = 0; j < ctx->entry[i].numattrs; j++) {
free(ctx->entry[i].attributes[j]);
ctx->entry[i].attributes[j] = NULL;
}
if (ctx->entry[i].attributes) {
free(ctx->entry[i].attributes);
}
ctx->entry[i].attributes = NULL;
ctx->entry[i].numattrs = 0;
if (ctx->entry[i].filter) {
free(ctx->entry[i].filter);
}
ctx->entry[i].filter = NULL;
}
if (ctx->entry) {
free(ctx->entry);
}
ctx->entry = NULL;
ctx->entries = 0;
if (ctx->conf) {
scconf_free(ctx->conf);
}
ctx->conf = NULL;
free(ctx);
ctx = NULL;
}
}
void scldap_parse_arguments(scldap_context ** ctx, int argc, const char **argv)
{
scldap_context *ptr = *ctx;
int i;
if (!ptr || !argv || argc < 0)
return;
for (i = 0; i < argc; i++) {
if (argv[i][0] == '-') {
char *optarg = (char *) argv[i + 1];
if (!optarg)
continue;
switch (argv[i][1]) {
#define ADD(x) \
{ \
if (x) { \
free(x); \
x = NULL; \
} \
x = ((optarg) ? strdup(optarg) : NULL); \
}
case 'A':
scldap_add_entry(ptr, optarg);
break;
case 'E':
scldap_set_entry(ptr, optarg);
break;
case 'H':
ADD(ptr->entry[ptr->active].ldaphost);
break;
case 'P':
ptr->entry[ptr->active].ldapport = atoi(optarg);
break;
case 'S':
ptr->entry[ptr->active].scope = atoi(optarg);
break;
case 'b':
ADD(ptr->entry[ptr->active].binddn);
break;
case 'p':
ADD(ptr->entry[ptr->active].passwd);
break;
case 'B':
ADD(ptr->entry[ptr->active].base);
break;
case 'a':
if (ptr->entry[ptr->active].numattrs >= SCLDAP_MAX_ATTRIBUTES) {
break;
}
ptr->entry[ptr->active].attributes = (char **) realloc(ptr->entry[ptr->active].attributes, (ptr->entry[ptr->active].numattrs + 2) * sizeof(char *));
if (!ptr->entry[ptr->active].attributes)
break;
memset(&ptr->entry[ptr->active].attributes[ptr->entry[ptr->active].numattrs], 0, sizeof(char *));
ADD(ptr->entry[ptr->active].attributes[ptr->entry[ptr->active].numattrs]);
ptr->entry[ptr->active].numattrs++;
ptr->entry[ptr->active].attributes[ptr->entry[ptr->active].numattrs] = NULL;
break;
case 'f':
ADD(ptr->entry[ptr->active].filter);
#undef ADD
break;
case 'L':
{
scldap_context *tmp = scldap_parse_parameters(optarg);
if (tmp) {
scldap_free_parameters(ptr);
ptr = tmp;
}
}
break;
}
}
}
*ctx = ptr;
}
const char *scldap_show_arguments(void)
{
static char buf[250];
memset(buf, 0, 250);
snprintf(buf, 250,
" -L ldap.conf Configuration file to load\n"
" -A entry Add new entry\n"
" -E entry Set current entry\n"
" LDAP entry specific options:\n"
" -H hostname\n"
" -P port\n"
" -S scope\n"
" -b binddn\n"
" -p passwd\n"
" -B base\n"
" -a attribute(s)\n"
" -f filter\n");
return &buf[0];
}
int scldap_add_entry(scldap_context * ctx, const char *entry)
{
unsigned int i;
if (!ctx)
return 0;
if (entry) {
for (i = 0; i < ctx->entries; i++) {
if (!ctx->entry[i].entry) {
ctx->entry[i].entry = strdup(entry);
ctx->active = i;
return i;
}
}
i = ctx->entries;
ctx->entry = (scldap_param_entry *) realloc(ctx->entry, (i + 2) * sizeof(scldap_param_entry));
if (!ctx->entry)
return 0;
memset(&ctx->entry[i], 0, sizeof(scldap_param_entry));
ctx->entry[i].entry = strdup(entry);
ctx->active = i;
ctx->entries++;
return i;
}
return 0;
}
int scldap_get_entry(scldap_context * ctx, const char *entry)
{
unsigned int i;
if (!ctx)
return 0;
if (entry) {
for (i = 0; i < ctx->entries; i++) {
if (ctx->entry[i].entry) {
if (!strcmp(ctx->entry[i].entry, entry)) {
return i;
}
}
}
}
return 0;
}
void scldap_set_entry(scldap_context * ctx, const char *entry)
{
unsigned int i;
if (!ctx)
return;
if (entry) {
for (i = 0; i < ctx->entries; i++) {
if (ctx->entry[i].entry) {
if (!strcmp(ctx->entry[i].entry, entry)) {
ctx->active = i;
break;
}
}
}
}
}
void scldap_remove_entry(scldap_context * ctx, const char *entry)
{
unsigned int i, j;
if (!ctx)
return;
if (entry) {
for (i = 0; i < ctx->entries; i++) {
if (ctx->entry[i].entry) {
if (!strcmp(ctx->entry[i].entry, entry)) {
if (ctx->entry[i].entry) {
free(ctx->entry[i].entry);
}
ctx->entry[i].entry = NULL;
if (ctx->entry[i].ldaphost) {
free(ctx->entry[i].ldaphost);
}
ctx->entry[i].ldaphost = NULL;
ctx->entry[i].ldapport = 0;
ctx->entry[i].scope = 0;
if (ctx->entry[i].binddn) {
free(ctx->entry[i].binddn);
}
ctx->entry[i].binddn = NULL;
if (ctx->entry[i].passwd) {
free(ctx->entry[i].passwd);
}
ctx->entry[i].passwd = NULL;
if (ctx->entry[i].base) {
free(ctx->entry[i].base);
}
ctx->entry[i].base = NULL;
for (j = 0; j < ctx->entry[i].numattrs; j++) {
free(ctx->entry[i].attributes[j]);
ctx->entry[i].attributes[j] = NULL;
}
if (ctx->entry[i].attributes) {
free(ctx->entry[i].attributes);
}
ctx->entry[i].attributes = NULL;
ctx->entry[i].numattrs = 0;
if (ctx->entry[i].filter) {
free(ctx->entry[i].filter);
}
ctx->entry[i].filter = NULL;
break;
}
}
}
}
}
int scldap_is_valid_url(const char *url)
{
if (!url)
return 0;
return ldap_is_ldap_url((char *) url);
}
int scldap_url_to_entry(scldap_context * ctx, const char *entry, const char *url)
{
LDAPURLDesc *ldapurl = NULL;
int rv, i, j;
if (!ctx || !entry || !url) {
return -1;
}
rv = ldap_url_parse((char *) url, &ldapurl);
if (rv) {
switch (rv) {
#ifdef LDAP_URL_ERR_BADSCHEME
case LDAP_URL_ERR_BADSCHEME:
fprintf(stderr, "Not an LDAP URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_BADENCLOSURE
case LDAP_URL_ERR_BADENCLOSURE:
fprintf(stderr, "Bad enclosure in URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_BADURL
case LDAP_URL_ERR_BADURL:
fprintf(stderr, "Bad URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_BADHOST
case LDAP_URL_ERR_BADHOST:
fprintf(stderr, "Host is invalid in URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_BADATTRS
case LDAP_URL_ERR_BADATTRS:
fprintf(stderr, "Attributes are invalid in URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_BADSCOPE
case LDAP_URL_ERR_BADSCOPE:
fprintf(stderr, "Scope is invalid in URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_BADFILTER
case LDAP_URL_ERR_BADFILTER:
fprintf(stderr, "Filter is invalid in URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_BADEXTS
case LDAP_URL_ERR_BADEXTS:
fprintf(stderr, "Extensions are invalid in URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_MEM
case LDAP_URL_ERR_MEM:
fprintf(stderr, "Out of memory parsing URL: %s", url);
break;
#endif
#ifdef LDAP_URL_ERR_PARAM
case LDAP_URL_ERR_PARAM:
fprintf(stderr, "Bad parameter parsing URL: %s", url);
break;
#endif
default:
fprintf(stderr, "Unknown error %d parsing URL: %s", rv, url);
break;
}
return -1;
}
if (ldapurl) {
scldap_remove_entry(ctx, entry);
scldap_add_entry(ctx, entry);
i = scldap_get_entry(ctx, entry);
#define ADD(val) ((val) ? strdup(val) : NULL)
ctx->entry[i].ldaphost = ADD(ldapurl->lud_host);
ctx->entry[i].ldapport = ldapurl->lud_port;
ctx->entry[i].scope = ldapurl->lud_scope;
ctx->entry[i].base = ADD(ldapurl->lud_dn);
for (j = 0; ldapurl->lud_attrs[j]; j++) {
if (ctx->entry[i].numattrs >= SCLDAP_MAX_ATTRIBUTES) {
break;
}
ctx->entry[i].attributes = (char **) realloc(ctx->entry[i].attributes, (ctx->entry[i].numattrs + 2) * sizeof(char *));
if (!ctx->entry[i].attributes)
break;
memset(&ctx->entry[i].attributes[ctx->entry[i].numattrs], 0, sizeof(char *));
ctx->entry[i].attributes[ctx->entry[i].numattrs] = strdup(ldapurl->lud_attrs[j]);
ctx->entry[i].numattrs++;
ctx->entry[i].attributes[ctx->entry[i].numattrs] = NULL;
}
ctx->entry[i].filter = ADD(ldapurl->lud_filter);
#undef ADD
ldap_free_urldesc(ldapurl);
ldapurl = NULL;
return 0;
}
return -1;
}
int scldap_approx_base_by_dn(scldap_context * ctx, const char *entry, const char *dn, char **base)
{
scldap_result *splitdn = NULL;
unsigned int i = 0, j = 0, numdns = 0;
char **founddns = NULL;
if (!ctx || !entry || !dn) {
return -1;
}
if (scldap_dn_to_result(dn, &splitdn, 0) < 0) {
return -1;
}
for (i = 0; i < splitdn->results; i++) {
scldap_result *result = NULL;
#if 0
printf("%02i. %s [%li]\n", i + 1,
splitdn->result[i].data,
splitdn->result[i].datalen);
#endif
if (scldap_search(ctx, entry, &result, 0, (const char *) splitdn->result[i].data) < 0) {
continue;
}
if (result) {
for (j = 0; j < result->results; j++) {
founddns = (char **) realloc(founddns, (numdns + 2) * sizeof(char *));
founddns[numdns] = strdup(result->result[j].dn);
numdns++;
founddns[numdns] = NULL;
}
scldap_free_result(result);
}
}
scldap_free_result(splitdn);
if (!numdns) {
return -1;
}
#if 0
for (i = 0; i < numdns; i++) {
printf("%02i. %s\n", i + 1, founddns[i]);
}
#endif
if (*base) {
free(*base);
*base = NULL;
}
/* FIXME: Add proper logic to this */
*base = strdup(founddns[0]);
for (i = 0; i < numdns; i++) {
free(founddns[i]);
}
free(founddns);
return 1;
}
int scldap_dn_to_result(const char *dn, scldap_result ** result, int notypes)
{
scldap_result *_result = NULL;
char *buf = NULL, **tmp = NULL;
unsigned int i;
if (!dn || *result)
return -1;
_result = (scldap_result *) malloc(sizeof(scldap_result));
if (!_result) {
return -1;
}
memset(_result, 0, sizeof(scldap_result));
#if 0
printf("dn: %s\n", dn);
#endif
buf = (char *) malloc((strlen(dn) + 1) * 2);
if (!buf) {
free(_result);
return -1;
}
memset(buf, 0, (strlen(dn) + 1) * 2);
if (dn[0] == '/') {
unsigned int c = 0;
for (i = 1; i < strlen(dn); i++) {
if (dn[i] == '/') {
buf[c++] = ',';
buf[c++] = ' ';
} else {
buf[c++] = dn[i];
}
}
} else {
memcpy(buf, dn, strlen(dn));
}
#if 0
printf("buf: %s\n", buf);
#endif
tmp = ldap_explode_dn(buf, notypes);
for (i = 0; tmp[i]; i++) {
_result->result = (scldap_result_entry *) realloc(_result->result, (_result->results + 2) * sizeof(scldap_result_entry));
if (!_result->result)
continue;
memset(&_result->result[_result->results], 0, sizeof(scldap_result_entry));
_result->result[_result->results].dn = strdup(buf);
_result->result[_result->results].data = (unsigned char *) strdup(tmp[i]);
_result->result[_result->results].datalen = strlen(tmp[i]);
_result->results++;
free(tmp[i]);
}
free(buf);
free(tmp);
if (!_result->results) {
scldap_free_result(_result);
return -1;
}
*result = _result;
return 0;
}
static void scldap_get_result(LDAP * ld, LDAPMessage * res, scldap_param_entry * param, scldap_result * result, int attrsonly)
{
struct berval **bvals = NULL;
BerElement *ber = NULL;
char *name = NULL;
unsigned int i = 0, j, o;
for (name = ldap_first_attribute(ld, res, &ber); name;
name = ldap_next_attribute(ld, res, ber)) {
#define ADD() \
{ \
if (result->results < SCLDAP_MAX_RESULTS) { \
result->result[result->results].name = strdup(name); \
result->result[result->results].dn = ldap_get_dn(ld, res); \
if (!attrsonly) { \
result->result[result->results].datalen = bvals[i]->bv_len; \
result->result[result->results].data = (unsigned char *) malloc(result->result[result->results].datalen + 1); \
memset(result->result[result->results].data, 0, result->result[result->results].datalen + 1); \
memcpy(result->result[result->results].data, bvals[i]->bv_val, result->result[result->results].datalen); \
for (o = 0; o < bvals[i]->bv_len; o++) { \
int k = bvals[i]->bv_val[o]; \
if (!isascii(k)) { \
result->result[result->results].binary = 1; \
break; \
} \
} \
} \
result->results++; \
result->result = (scldap_result_entry *) realloc(result->result, (result->results + 2) * sizeof(scldap_result_entry)); \
memset(&result->result[result->results], 0, sizeof(scldap_result_entry)); \
} \
}
if (attrsonly) {
if (param->numattrs) {
for (j = 0; j < param->numattrs; j++) {
if (!strncasecmp(param->attributes[j], name, strlen(param->attributes[j]))) {
ADD();
}
}
} else {
ADD();
}
} else if ((bvals = ldap_get_values_len(ld, res, name))) {
for (i = 0; bvals[i]; i++) {
if (param->numattrs) {
for (j = 0; j < param->numattrs; j++) {
if (!strncasecmp(param->attributes[j], name, strlen(param->attributes[j]))) {
ADD();
}
}
} else {
ADD();
#undef ADD
}
}
ber_bvecfree(bvals);
}
}
}
static char *combinestr(char *str,...)
{
#define MAX_BUF_LEN 4096
va_list ap;
char *buf = NULL;
if (!str) {
return NULL;
}
buf = (char *) malloc(MAX_BUF_LEN);
if (!buf) {
return NULL;
}
memset(buf, 0, MAX_BUF_LEN);
va_start(ap, str);
vsnprintf(buf, MAX_BUF_LEN, str, ap);
va_end(ap);
return buf;
#undef MAX_BUF_LEN
}
int scldap_search(scldap_context * ctx, const char *entry,
scldap_result ** result, unsigned int numwantedresults,
const char *searchpattern)
{
LDAPMessage *res, *e;
LDAP *ld = NULL;
scldap_result *_result = *result;
int rc, entrynum = -1;
char *pattern = NULL;
char **keepenv = NULL;
if (_result || !ctx) {
return -1;
}
entrynum = scldap_get_entry(ctx, entry);
if (entrynum < 0) {
return -1;
}
if (!ctx->entry[entrynum].ldaphost) {
return -1;
}
keepenv = environ;
environ = NULL;
if ((ld = ldap_init(ctx->entry[entrynum].ldaphost, ctx->entry[entrynum].ldapport)) == NULL) {
environ = keepenv;
perror("ldap_init");
return -1;
}
environ = keepenv;
if (ldap_bind_s(ld, ctx->entry[entrynum].binddn, ctx->entry[entrynum].passwd, LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) {
ldap_perror(ld, "ldap_bind");
ldap_unbind(ld);
return -1;
}
if (searchpattern && ctx->entry[entrynum].filter) {
pattern = combinestr(ctx->entry[entrynum].filter, searchpattern);
} else if (searchpattern && !ctx->entry[entrynum].filter) {
pattern = strdup(searchpattern);
} else if (!searchpattern && ctx->entry[entrynum].filter) {
pattern = strdup(ctx->entry[entrynum].filter);
}
/* This ifdef is currently not actually used or probed in any way,
* older versions of OpenLDAP, eg. <=1.2.12.1 seem to need this
* sanity check. This check cannot be enabled at least for newer
* versions of OpenLDAP, otherwise it'll block certificate CRL
* fetches. scldap used to work at least with solaris built-in
* ldap library, nowadays untested, so beware. -aet
*/
#ifdef HAVE_OLD_OPENLDAP
/* Note: pattern *can* be empty but NOT NULL! Therefore, this is illegal. */
if (!pattern) {
ldap_unbind(ld);
return -1;
}
#endif
#if 0
if (pattern)
fprintf(stderr, "pattern: %s\n", pattern);
#endif
if (ldap_search(ld, ctx->entry[entrynum].base, ctx->entry[entrynum].scope, pattern, ctx->entry[entrynum].attributes, ctx->entry[entrynum].attrsonly) == -1) {
ldap_perror(ld, "ldap_search");
if (pattern)
free(pattern);
ldap_unbind(ld);
return -1;
}
if (pattern)
free(pattern);
_result = (scldap_result *) malloc(sizeof(scldap_result));
if (!_result) {
ldap_unbind(ld);
return -1;
}
memset(_result, 0, sizeof(scldap_result));
while ((rc = ldap_result(ld, LDAP_RES_ANY, 0, NULL, &res)) == LDAP_RES_SEARCH_ENTRY) {
e = ldap_first_entry(ld, res);
if (_result->results < SCLDAP_MAX_RESULTS) {
_result->result = (scldap_result_entry *) realloc(_result->result, (_result->results + 2) * sizeof(scldap_result_entry));
if (!_result->result)
break;
memset(&_result->result[_result->results], 0, sizeof(scldap_result_entry));
scldap_get_result(ld, e, &ctx->entry[entrynum], _result, ctx->entry[entrynum].attrsonly);
}
ldap_msgfree(res);
}
if (rc == -1) {
ldap_perror(ld, "ldap_result");
ldap_msgfree(res);
ldap_unbind(ld);
scldap_free_result(_result);
return rc;
}
if ((rc = ldap_result2error(ld, res, 0)) != LDAP_SUCCESS) {
ldap_perror(ld, "ldap_search");
}
ldap_msgfree(res);
ldap_unbind(ld);
if (numwantedresults) {
if (numwantedresults != _result->results) {
scldap_free_result(_result);
_result = NULL;
rc = -1;
}
}
*result = _result;
return rc;
}
void scldap_free_result(scldap_result * result)
{
unsigned int i;
if (result) {
for (i = 0; i < result->results; i++) {
if (result->result[i].name) {
free(result->result[i].name);
}
result->result[i].name = NULL;
if (result->result[i].dn) {
free(result->result[i].dn);
}
result->result[i].dn = NULL;
if (result->result[i].data) {
free(result->result[i].data);
}
result->result[i].data = NULL;
result->result[i].datalen = 0;
}
if (result->result) {
free(result->result);
}
result->result = NULL;
result->results = 0;
free(result);
result = NULL;
}
}

View File

@ -1,141 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2001, 2002
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SC_LDAP_H
#define _SC_LDAP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <opensc/scconf.h>
/* Hard limit, tables are allocated dynamically */
#define SCLDAP_MAX_ENTRIES 16
#define SCLDAP_MAX_ATTRIBUTES 32
#define SCLDAP_MAX_RESULTS 64
typedef struct _scldap_param_entry {
char *entry;
char *ldaphost;
unsigned int ldapport;
unsigned int scope;
char *binddn;
char *passwd;
char *base;
unsigned int attrsonly, numattrs;
char **attributes;
char *filter;
} scldap_param_entry;
typedef struct _scldap_context {
unsigned entries, active;
scconf_context *conf;
scldap_param_entry *entry;
} scldap_context;
typedef struct _scldap_result_entry {
char *name;
char *dn;
unsigned char *data;
unsigned long datalen;
unsigned int binary;
} scldap_result_entry;
typedef struct _scldap_result {
unsigned results;
scldap_result_entry *result;
} scldap_result;
/* Allocate scldap_context
* The filename can be NULL
*/
extern scldap_context *scldap_parse_parameters(const char *filename);
/* Print all entries and configurations to stdout
*/
extern void scldap_show_parameters(scldap_context * ctx);
/* Free scldap_context
*/
extern void scldap_free_parameters(scldap_context * ctx);
/* Parse command line arguments
*/
extern void scldap_parse_arguments(scldap_context ** ctx, int argc, const char **argv);
/* Return a string that contains all
* known command line arguments
*/
extern const char *scldap_show_arguments(void);
/* Add new configuration entry
*/
extern int scldap_add_entry(scldap_context * ctx, const char *entry);
/* Return entry index number
*/
extern int scldap_get_entry(scldap_context * ctx, const char *entry);
/* Set entry as the current active entry
*/
extern void scldap_set_entry(scldap_context * ctx, const char *entry);
/* Remove entry and all configurations for it
*/
extern void scldap_remove_entry(scldap_context * ctx, const char *entry);
/* See if the string is a valid URL
* Returns 1 = ok, 0 = not valid
*/
extern int scldap_is_valid_url(const char *url);
/* Convert URL to a search entry
*/
extern int scldap_url_to_entry(scldap_context * ctx, const char *entry, const char *url);
extern int scldap_approx_base_by_dn(scldap_context * ctx, const char *entry, const char *dn, char **base);
/* Split DN to result entries
*
* If notypes is a non-zero, just values
* will be added to result entries
*/
extern int scldap_dn_to_result(const char *dn, scldap_result ** result, int notypes);
/* Search data from LDAP server
*
* If numwantedresults is a non-zero, we require
* that the given value will match with the number
* of the actual results we have got from the server
*/
extern int scldap_search(scldap_context * ctx, const char *entry,
scldap_result ** result, unsigned int numwantedresults,
const char *searchpattern);
/* Free search results
*/
extern void scldap_free_result(scldap_result * result);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,216 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2001, 2002
* Antti Tapaninen <aet@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 <sys/types.h>
#include "scldap.h"
static void hex_dump_asc(FILE * f, const unsigned char *in, size_t count, int addr)
{
int lines = 0;
while (count) {
char ascbuf[17];
unsigned int i;
if (addr >= 0) {
fprintf(f, "%08X: ", addr);
addr += 16;
}
for (i = 0; i < count && i < 16; i++) {
fprintf(f, "%02X ", *in);
if (isprint(*in))
ascbuf[i] = *in;
else
ascbuf[i] = '.';
in++;
}
count -= i;
ascbuf[i] = 0;
for (; i < 16 && lines; i++)
fprintf(f, " ");
fprintf(f, "%s\n", ascbuf);
lines++;
}
}
static void usage(void)
{
printf("test-ldap: [options]\n");
printf(" -h Show help\n");
printf("%s", scldap_show_arguments());
printf(" -e <entry> Use <entry> for search.\n\t\tAn URL is also accepted.\n");
printf(" -s <string> Fill the entry filter with a string.\n\t\tAlso used as a replacement for filter\n\t\twhen no entry filter found.\n");
printf(" -F Save results(s).\n");
printf(" -d Dump result(s) to screen in hex format.\n");
printf(" -v Increase verbose level.\n");
}
int main(int argc, char **argv)
{
char *entry = NULL, *searchword = NULL;
unsigned int i, verbose = 0, dump = 0, save = 0, ffound = 0;
scldap_context *lctx = NULL;
scldap_result *lresult = NULL;
for (i = 0; i < (unsigned int) argc; i++) {
if (argv[i][0] == '-') {
char *optarg = (char *) argv[i + 1];
switch (argv[i][1]) {
case 'e':
if (!optarg)
continue;
entry = optarg;
break;
case 's':
if (!optarg)
continue;
searchword = optarg;
break;
case 'F':
save = 1;
break;
case 'd':
dump = 1;
break;
case 'v':
verbose++;
break;
case 'h':
case '?':
usage();
return 1;
break;
}
}
}
lctx = scldap_parse_parameters(SCLDAP_CONF_PATH);
if (!lctx) {
return 1;
}
if (verbose > 2)
scldap_show_parameters(lctx);
scldap_parse_arguments(&lctx, argc, (const char **) argv);
if (scldap_is_valid_url(entry)) {
/* Valid test URL:
* "ldap://193.229.0.210:389/cn=finsign%20ca%20for%20test3,o=vrk-fin
* sign%20gov.%20ca,dmdname=fineid,c=FI?certificaterevocationlist"
*/
char *entryname = "LDAP URL";
if (verbose)
printf("Valid url.\n");
if (scldap_url_to_entry(lctx, entryname, entry) < 0) {
printf("scldap_url_to_entry failed.\n");
scldap_free_parameters(lctx);
return 1;
}
scldap_set_entry(lctx, entryname);
entry = entryname;
}
if (lctx->entry[lctx->active].filter || searchword) {
ffound = 1;
}
if (!lctx->entries && (!ffound && !entry)) {
usage();
printf("\nMissing entry for the search or the current\n");
printf("entry needs to be filled in with a searchword.\n");
scldap_free_parameters(lctx);
return 1;
}
if (verbose > 2)
scldap_show_parameters(lctx);
if (scldap_search(lctx, entry, &lresult, 0, searchword) < 0) {
fprintf(stderr, "scldap_search failed.\n");
scldap_free_parameters(lctx);
return 1;
}
printf("Success. (%i results)\n", lresult->results);
for (i = 0; i < lresult->results; i++) {
if (verbose)
printf("%02i. %s[%li] = %s\n", i + 1,
lresult->result[i].name, lresult->result[i].datalen,
(lresult->result[i].binary ? "NOT ASCII" : (char *) lresult->result[i].data));
if (verbose > 1)
printf("%02i. dn = %s\n", i + 1, lresult->result[i].dn);
if (dump)
hex_dump_asc(stdout, lresult->result[i].data, lresult->result[i].datalen, 0);
if (save && lresult->result[i].name) {
const char *prefix = "ldap-dump-";
int filenamelen = strlen(lresult->result[i].name) + strlen(prefix) + 6;
char *filename = (char *) malloc(filenamelen);
FILE *fp = NULL;
if (!filename)
break;
memset(filename, 0, filenamelen);
snprintf(filename, filenamelen, "%s%02i-", prefix, i + 1);
strcat(filename, lresult->result[i].name);
if ((fp = fopen(filename, "a"))) {
fwrite(lresult->result[i].data, lresult->result[i].datalen, 1, fp);
fclose(fp);
} else {
perror("fopen");
}
free(filename);
}
}
scldap_free_result(lresult);
lresult = NULL;
#if 0
if (scldap_dn_to_result("C=FI, S=HST-KORTTI, G=ESIMERKKI679, CN=HST-KORTTI ESIMERKKI679 99999578U, SN=99999578U", &lresult, 1) < 0) {
printf("scldap_dn_to_result failed.\n");
scldap_free_parameters(lctx);
return 1;
}
for (i = 0; i < lresult->results; i++) {
printf("%02i. %s [%li]\n", i + 1,
lresult->result[i].data,
lresult->result[i].datalen);
}
scldap_free_result(lresult);
lresult = NULL;
#endif
#if 0
{
char *binddn = NULL;
if (scldap_approx_binddn_by_dn(lctx, "approx_binddn", "C=FI, O=VRK-FINSIGN Gov. CA, CN=FINSIGN CA for Test3", &binddn) < 0) {
printf("scldap_approx_binddn_by_dn failed.\n");
scldap_free_parameters(lctx);
return 1;
}
printf("binddn: %s\n", binddn);
free(binddn);
}
#endif
scldap_free_parameters(lctx);
return 0;
}

View File

@ -1,21 +0,0 @@
# Process this file with automake to create Makefile.in
libdir = @libdir@/security
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = @CPPFLAGS@ -I${top_srcdir}/src/scam
AM_LDFLAGS = @LIBDL@ ${top_builddir}/src/scam/libscam.la
SRC = sia_opensc.c sia_support.c sia_support.h
if HAVE_SIA
lib_LTLIBRARIES = libsia_opensc.la
noinst_PROGRAMS = test-sia
endif
libsia_opensc_la_SOURCES = $(SRC)
libsia_opensc_la_LDFLAGS = -module -avoid-version
test_sia_SOURCES = test-sia.c

View File

@ -1,459 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@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 <stdarg.h>
#include <pwd.h>
#include <sys/types.h>
#include "sia_support.h"
#include "scam.h"
static scam_context sctx = {0,};
typedef struct _scam_msg_data {
sia_collect_func_t *collect;
SIAENTITY *entity;
} scam_msg_data;
static void printmsg(scam_context * sctx, char *str)
{
scam_msg_data *msg = (scam_msg_data *) sctx->msg_data;
if (msg->collect)
sia_warning(msg->collect, str);
}
static void logmsg(scam_context * sctx, char *str)
{
scam_msg_data *msg = (scam_msg_data *) sctx->msg_data;
opensc_sia_log(str);
}
/* siad_init - Once per reboot processing goes here. */
int siad_init(void)
{
return SIADSUCCESS;
}
/* malloc any needed space required over the authentication session here. */
int siad_ses_init(SIAENTITY * entity, int pkgind)
{
return SIADSUCCESS;
}
/* We set the pwd entry in siad_ses_authent if we succeed in authenticating.
* Otherwise the BSD mechanism will incur a core dump.
*/
int siad_ses_estab(sia_collect_func_t * collect, SIAENTITY * entity, int pkgind)
{
return SIASUCCESS;
}
int siad_ses_launch(sia_collect_func_t * collect, SIAENTITY * entity, int pkgind)
{
return SIADSUCCESS;
}
/* Free up space malloc'd in siad_ses_init() */
int siad_ses_release(SIAENTITY * entity, int pkgind)
{
return SIADSUCCESS;
}
int siad_get_groups(struct sia_context *context, const char *username,
gid_t * buf, int *numgroups, int maxgroups)
{
log_message("siad_get_groups returning failure.\n");
return SIADFAIL;
}
/* siad_get_name_password
* Common code for siad_ses_authent and siad_ses_reauthent. Gather name and
* password if required.
*
* Arguments:
* collect - prompt collection function.
* entity - SIA entity
* got_pass - set to 1 if we gather'd the password ourselves.
*
*
* Return value:
* SIADFAIL - failed to malloc, calling routine should return SIADFAIL.
* SIADSUCESS - name and password have been collected (maybe not by us).
* SIADFAIL | SIADSTOP - calling routine should return.
*/
int siad_get_name_password(sia_collect_func_t * collect, SIAENTITY * entity,
const char *pinentry,
int *got_pass)
{
int need_name = 0, need_pass = 0, code = SIADFAIL;
struct prompt_t prompts[2];
const char *str = pinentry ? pinentry : DEFAULT_PINENTRY;
int n_prompts = 0;
*got_pass = 0;
if ((!entity->name) || (!(*entity->name))) {
entity->name = malloc(SIANAMEMIN + 1);
if (entity->name == NULL) {
log_message("siad_get_name_password: failed to malloc name.\n");
code = SIADFAIL;
goto fail_free;
}
*(entity->name) = '\0';
need_name = 1;
}
if ((!entity->password) || (!(*entity->password))) {
entity->password = malloc(SIAMXPASSWORD + 1);
if (entity->password == NULL) {
log_message("siad_get_name_password: failed to malloc password.\n");
code = SIADFAIL;
goto fail_free;
}
*(entity->password) = '\0';
need_pass = 1;
}
if (need_name || need_pass) {
if (!collect || !entity->colinput) {
code = SIADFAIL;
goto fail_free;
}
if (need_name) {
prompts[n_prompts].prompt = (unsigned char *) "login: ";
prompts[n_prompts].result = (unsigned char *) entity->name;
prompts[n_prompts].min_result_length = 1;
prompts[n_prompts].max_result_length = SIANAMEMIN;
prompts[n_prompts].control_flags = SIAPRINTABLE;
n_prompts++;
}
if (need_pass) {
prompts[n_prompts].prompt = (unsigned char *) str;
prompts[n_prompts].result = (unsigned char *) entity->password;
prompts[n_prompts].min_result_length = 0;
prompts[n_prompts].max_result_length = SIAMXPASSWORD;
prompts[n_prompts].control_flags = SIARESINVIS;
n_prompts++;
}
if (n_prompts > 1)
code = (*collect) (0, SIAFORM, (uchar_t *) "", n_prompts, prompts);
else
code = (*collect) (240, SIAONELINER, (uchar_t *) "", 1, prompts);
if (code != SIACOLSUCCESS) {
code = SIADFAIL | SIADSTOP;
goto fail_free;
}
}
*got_pass = need_pass;
return SIADSUCCESS;
fail_free:
if (need_name) {
free(entity->name);
}
entity->name = NULL;
if (need_pass) {
free(entity->password);
}
entity->password = NULL;
return code;
}
/* siad_ses_authent
* Authenticate user for sia_opensc.
*
* This is an integrated login environment.
*
* entityhdl->colinput == 1 means the collect function can be used to prompt
* for input. If it's 0, then it can only be used to print messages.
* For this case, one also has to test for a non-null collect function.
*/
int siad_ses_authent(sia_collect_func_t * collect, SIAENTITY * entity,
int siastat, int pkgind)
{
int got_pass = 0;
int code = 0, rv;
const char *pinentry = NULL;
struct passwd *pwd = NULL;
memset(&sctx, 0, sizeof(scam_context));
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) {
code = SIADFAIL;
goto authent_fail;
}
rv = scam_init(&sctx, 0, NULL);
if (rv != SCAM_SUCCESS) {
code = SIADFAIL;
goto authent_fail;
}
pinentry = scam_pinentry(&sctx);
code = siad_get_name_password(collect, entity, pinentry, &got_pass);
if (code != SIADSUCCESS) {
goto authent_fail;
}
pwd = getpwnam(entity->name);
if (!pwd) {
/* Only authenticate if user is in /etc/passwd. */
code = SIADFAIL;
goto authent_fail;
}
if ((pwd->pw_passwd[0] == '*') && (pwd->pw_passwd[1] == '\0')) {
log_message("siad_ses_authent: refusing to authenticate\n");
code = SIADFAIL;
goto authent_fail;
}
code = scam_auth(&sctx, 0, NULL, entity->name, entity->password);
if (code != SCAM_SUCCESS) {
log_message("siad_sis_authent: auth1 failure\n");
code = SIADFAIL;
goto authent_fail;
}
if (!entity->pwd) {
entity->pwd = (struct passwd *) malloc(sizeof(struct passwd));
if (!entity->pwd) {
code = SIADFAIL;
goto authent_fail;
}
memset((void *) entity->pwd, '\0', sizeof(struct passwd));
if (sia_make_entity_pwd(pwd, entity) != SIASUCCESS) {
log_message("siad_ses_authent: Can't set pwd into entity.\n");
code = SIADFAIL;
goto authent_fail;
}
}
log_message("siad_ses_authent returning success.\n");
opensc_sia_log("siad_ses_authent returning success.\n");
scam_deinit(&sctx);
return SIADSUCCESS;
authent_fail:
opensc_sia_log("siad_ses_authent fails, code=%d.\n", code);
log_message("siad_ses_authent fails, code=%d.\n", code);
scam_deinit(&sctx);
return code;
}
/* siad_ses_reauthent.
* Used for such things as as locking/unlocking terminal. This implies
* authenticate, but do not set a pag. The oher differences is that we
* accept vouching from other mechanism.
*
* Note the dtsession collects the password itself and will always pass it
* in. Also, colinput is typically false in this case as well as collect
* being null.
*/
int siad_ses_reauthent(sia_collect_func_t * collect, SIAENTITY * entity,
int siastat, int pkgind)
{
int got_pass = 0;
int code = 0, rv;
const char *pinentry = NULL;
struct passwd *pwd = NULL;
if (siastat == SIADSUCCESS)
return SIADSUCCESS;
memset(&sctx, 0, sizeof(scam_context));
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) {
code = SIADFAIL;
goto reauthent_fail;
}
rv = scam_init(&sctx, 0, NULL);
if (rv != SCAM_SUCCESS) {
code = SIADFAIL;
goto reauthent_fail;
}
pinentry = scam_pinentry(&sctx);
code = siad_get_name_password(collect, entity, pinentry, &got_pass);
if (code != SIADSUCCESS) {
goto reauthent_fail;
}
pwd = getpwnam(entity->name);
if (!pwd) {
code = SIADFAIL;
goto reauthent_fail;
}
code = scam_auth(&sctx, 0, NULL, entity->name, entity->password);
if (code != SCAM_SUCCESS) {
log_message("siad_sis_reauthent: auth failure\n");
code = SIADFAIL;
goto reauthent_fail;
}
if (!entity->pwd) {
entity->pwd = (struct passwd *) malloc(sizeof(struct passwd));
if (!entity->pwd) {
code = SIADFAIL;
goto reauthent_fail;
}
memset((void *) entity->pwd, '\0', sizeof(struct passwd));
if (sia_make_entity_pwd(pwd, entity) != SIASUCCESS) {
log_message("siad_ses_reauthent: Can't set pwd into entity.\n");
code = SIADFAIL;
goto reauthent_fail;
}
}
log_message("siad_ses_reauthent returning success.\n");
opensc_sia_log("siad_ses_reauthent returning success.\n");
scam_deinit(&sctx);
return SIADSUCCESS;
reauthent_fail:
opensc_sia_log("siad_ses_reauthent fails, code=%d.\n", code);
log_message("siad_ses_reauthent fails, code=%d.\n", code);
scam_deinit(&sctx);
return code;
}
int siad_chk_invoker(void)
{
log_message("siad_chk_invoker returning failure.\n");
return SIADFAIL;
}
int siad_ses_suauthent(sia_collect_func_t * collect, SIAENTITY * entity,
int siastat, int pkgind)
{
log_message("siad_ses_suauthent returning failure.\n");
return SIADFAIL;
}
int siad_chg_finger(sia_collect_func_t * collect, const char *username,
int argc, char *argv[])
{
log_message("siad_chg_finger returning failure.\n");
return SIADFAIL;
}
int siad_chg_password(sia_collect_func_t * collect, const char *username,
int argc, char *argv[])
{
log_message("siad_chg_passwd returning failure.\n");
return SIADFAIL;
}
int siad_chg_shell(sia_collect_func_t * collect, const char *username,
int argc, char *argv[])
{
log_message("siad_chg_shell returning failure.\n");
return SIADFAIL;
}
int siad_getpwent(struct passwd *result, char *buf, int bufsize,
struct sia_context *context)
{
log_message("siad_getpwent returning failure.\n");
return SIADFAIL;
}
int siad_getpwuid(uid_t uid, struct passwd *result, char *buf, int bufsize,
struct sia_context *context)
{
log_message("siad_getpwuid returning failure.\n");
return SIADFAIL;
}
int siad_getpwnam(const char *name, struct passwd *result, char *buf,
int bufsize, struct sia_context *context)
{
log_message("siad_ses_getpwnam returning failure.\n");
return SIADFAIL;
}
int siad_setpwent(struct sia_context *context)
{
log_message("siad_ses_setpwent returning failure.\n");
return SIADFAIL;
}
int siad_endpwent(struct sia_context *context)
{
log_message("siad_ses_endpwent returning failure.\n");
return SIADFAIL;
}
int siad_getgrent(struct group *result, char *buf, int bufsize,
struct sia_context *context)
{
log_message("siad_ses_getgrent returning failure.\n");
return SIADFAIL;
}
int siad_getgrgid(gid_t gid, struct group *result, char *buf, int bufsize,
struct sia_context *context)
{
log_message("siad_ses_getgrgid returning failure.\n");
return SIADFAIL;
}
int siad_getgrnam(const char *name, struct group *result, char *buf,
int bufsize, struct sia_context *context)
{
log_message("siad_ses_getgrnam returning failure.\n");
return SIADFAIL;
}
int siad_setgrent(struct sia_context *context)
{
log_message("siad_ses_setgrent returning failure.\n");
return SIADFAIL;
}
int siad_endgrent(struct sia_context *context)
{
log_message("siad_ses_endgrent returning failure.\n");
return SIADFAIL;
}
int siad_chk_user(const char *logname, int checkflag)
{
log_message("siad_ses_chk_user returning success.\n");
return SIADFAIL;
}
#ifdef notdef
/* These are not in the current implementation. */
void siad_ses_toggle_privs(SIAENTITY * entity, int pkgind, int elevate)
{
log_message("siad_ses_toggle_privs.\n");
return;
}
void siad_ses_update_audit_record(SIAENTITY * entity, int pkgind, int event,
char *tokenp, char **datap, int *used,
int maxused)
{
log_message("siad_ses_update_audit_record.\n");
return;
}
#endif

View File

@ -1,38 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@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 <stdarg.h>
#include <pwd.h>
#include <sys/types.h>
#include "sia_support.h"
/* opensc_sia_log logs to the standard sialog. */
void opensc_sia_log(char *format,...)
{
va_list args;
va_start(args, format);
sia_log("sia_opensc", format, args);
va_end(args);
}

View File

@ -1,39 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@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.
*/
#ifndef _SIA_SUPPORT_H
#define _SIA_SUPPORT_H
#include <sia.h>
#include <siad.h>
#ifdef __cplusplus
extern "C" {
#endif
#define DEFAULT_PINENTRY "Enter PIN1: "
extern void opensc_sia_log(char *format,...);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,92 +0,0 @@
/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@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 <sgtty.h>
#include <utmp.h>
#include <signal.h>
#include <errno.h>
#include <ttyent.h>
#include <syslog.h>
#include <grp.h>
#include <pwd.h>
#include <setjmp.h>
#include <stdio.h>
#include <strings.h>
#include <lastlog.h>
#include <paths.h>
#include <sia.h>
#include <siad.h>
char *sia_code_string(int code)
{
static char err_string[64];
switch (code) {
case SIADSUCCESS:
return "SIADSUCCESS";
case SIAFAIL:
return "SIAFAIL";
case SIASTOP:
return "SIASTOP";
default:
(void) sprintf(err_string, "Unknown error %d\n", code);
return err_string;
}
}
int main(int argc, char **argv)
{
int (*sia_collect) () = sia_collect_trm;
SIAENTITY *entity = NULL;
char *user;
int code;
if (argc != 2) {
printf("Usage: test-sia user\n");
return 1;
}
user = argv[1];
code = sia_ses_init(&entity, argc, argv, NULL, user, NULL, 1, NULL);
if (code != SIASUCCESS) {
printf("sia_ses_init failed with code %s\n", sia_code_string(code));
sia_ses_release(&entity);
return 1;
}
code = sia_ses_reauthent(sia_collect, entity);
if (code != SIASUCCESS) {
printf("sia_ses_reauthent failed with code %s\n", sia_code_string(code));
sia_ses_release(&entity);
return 1;
}
code = sia_ses_release(&entity);
if (code != SIASUCCESS) {
printf("sia_ses_release failed with code %s\n", sia_code_string(code));
return 1;
}
printf("Password verified.\n");
return 0;
}