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:
parent
841694817c
commit
7de8272675
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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@
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
219
src/scam/scam.c
219
src/scam/scam.c
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue