- Added openscd and Assuan

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@763 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2002-12-10 13:43:23 +00:00
parent 0b8853a1a6
commit 9b6074b951
8 changed files with 720 additions and 1 deletions

View File

@ -1042,6 +1042,7 @@ src/Makefile
src/common/Makefile
src/include/Makefile
src/include/opensc/Makefile
src/assuan/Makefile
src/libopensc/Makefile
src/libopensc/opensc-config
src/openssh/Makefile
@ -1058,6 +1059,7 @@ src/signer/Makefile
src/signer/npinclude/Makefile
src/tests/Makefile
src/tools/Makefile
src/openscd/Makefile
])
if test ! -z "$RANDOM_POOL" ; then

View File

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

11
src/openscd/Makefile.am Normal file
View File

@ -0,0 +1,11 @@
# Process this file with automake to create Makefile.in
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = @CFLAGS_OPENSC@
AM_LDFLAGS = @LDFLAGS@ @LIBOPENSC@
bin_PROGRAMS = openscd
openscd_SOURCES = openscd.c commands.c mkdtemp.c
openscd_LDADD = @GETOPTSRC@ ../assuan/libassuan.a ../scrandom/libscrandom.a

364
src/openscd/commands.c Normal file
View File

@ -0,0 +1,364 @@
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include "../assuan/assuan.h"
#include "../libopensc/opensc.h"
#include "../libopensc/log.h"
#include "../libopensc/pkcs15.h"
#include "openscd.h"
static struct openscd_card * find_card(struct openscd_context *dctx,
struct sc_reader *reader,
int slot_id)
{
int i;
for (i = 0; i < dctx->card_count; i++) {
struct openscd_card *dcard = dctx->cards + i;
if (dcard->reader == reader && dcard->slot_id == slot_id)
return dcard;
}
return NULL;
}
static struct openscd_card * find_card_by_id(struct openscd_context *dctx,
int card_id)
{
int i;
for (i = 0; i < dctx->card_count; i++) {
struct openscd_card *dcard = dctx->cards + i;
if (dcard->card_id == card_id)
return dcard;
}
return NULL;
}
static void card_inserted(struct openscd_context *dctx,
struct sc_reader *reader,
int slot_id)
{
int n = dctx->card_count;
int r;
struct sc_card *card;
struct sc_pkcs15_card *p15card;
dctx->cards = realloc(dctx->cards, (n + 1) * sizeof(struct openscd_card));
assert(dctx->cards != NULL);
memset(dctx->cards + n, 0, sizeof(struct openscd_card));
dctx->cards[n].reader = reader;
dctx->cards[n].slot_id = slot_id;
r = sc_connect_card(reader, slot_id, &card);
if (r) {
error(dctx->ctx, "Unable to connect to card: %s\n", sc_strerror(r));
} else {
dctx->cards[n].card = card;
r = sc_pkcs15_bind(card, &p15card);
if (r) {
error(dctx->ctx, "Error with PKCS #15 card: %s\n", sc_strerror(r));
} else
dctx->cards[n].p15card = p15card;
}
dctx->cards[n].card_id = dctx->card_id_number;
pthread_mutex_init(&dctx->cards[n].mutex, NULL);
dctx->card_id_number++;
dctx->card_count++;
fprintf(stderr, "Card %d inserted.\n", dctx->cards[n].card_id);
}
static void card_removed(struct openscd_context *dctx,
struct openscd_card *dcard)
{
int idx;
fprintf(stderr, "Card %d removed.\n", dcard->card_id);
if (dcard->p15card != NULL) {
sc_pkcs15_unbind(dcard->p15card);
dcard->p15card = NULL;
}
if (dcard->card != NULL) {
/* This should fail... */
sc_disconnect_card(dcard->card, SC_DISCONNECT_AND_EJECT);
dcard->card = NULL;
}
for (idx = 0; idx < dctx->card_count; idx++) {
if (dctx->cards + idx == dcard) {
memmove(dctx->cards, dctx->cards + idx + 1,
dctx->card_count - (idx + 1));
break;
}
}
assert(idx != dctx->card_count);
dctx->card_count--;
dctx->cards = realloc(dctx->cards, dctx->card_count * sizeof(struct openscd_card));
assert(dctx->cards != NULL || dctx->card_count == 0);
}
static int cmd_list_readers(ASSUAN_CONTEXT actx, char *line)
{
struct openscd_context *dctx = assuan_get_pointer(actx);
int i, r;
for (i = 0; i < dctx->ctx->reader_count; i++) {
char line[80];
snprintf(line, sizeof(line), "%s", dctx->ctx->reader[i]->name);
r = assuan_send_data(actx, line, strlen(line));
if (r)
return r;
}
return 0;
}
static int cmd_list_cards(ASSUAN_CONTEXT actx, char *line)
{
struct openscd_context *dctx = assuan_get_pointer(actx);
int i, r = 0;
pthread_mutex_lock(&dctx->card_mutex);
for (i = 0; i < dctx->card_count; i++) {
char line[80];
snprintf(line, sizeof(line), "Card%d '%s' %d", dctx->cards[i].card_id,
dctx->cards[i].reader->name, dctx->cards[i].slot_id);
r = assuan_send_data(actx, line, strlen(line));
if (r)
break;
}
pthread_mutex_unlock(&dctx->card_mutex);
return 0;
}
static int cmd_get_objects(ASSUAN_CONTEXT actx, char *line)
{
struct openscd_context *dctx = assuan_get_pointer(actx);
struct openscd_card *dcard;
int card_id, obj_type, i, obj_count, r = 0;
struct sc_pkcs15_object *objs[32];
r = sscanf(line, "%X %X", &card_id, &obj_type);
if (r != 2)
return ASSUAN_Invalid_Command;
pthread_mutex_lock(&dctx->card_mutex);
dcard = find_card_by_id(dctx, card_id);
if (dcard != NULL)
pthread_mutex_lock(&dcard->mutex);
pthread_mutex_unlock(&dctx->card_mutex);
if (dcard == NULL)
return ASSUAN_Invalid_Card;
if (dcard->p15card == NULL) {
r = ASSUAN_No_PKCS15_App;
goto ret;
}
obj_count = sc_pkcs15_get_objects(dcard->p15card, obj_type, objs, 32);
if (obj_count < 0) {
/* FIXME */
r = ASSUAN_Card_Error;
goto ret;
}
for (i = 0; i < obj_count; i++) {
char *line;
line = malloc(objs[i]->der.len * 2 + 2);
if (line == NULL)
return ASSUAN_Out_Of_Core;
sc_bin_to_hex(objs[i]->der.value, objs[i]->der.len,
line, objs[i]->der.len * 2 + 2);
strcat(line, "\n");
r = assuan_send_data(actx, line, strlen(line));
free(line);
if (r)
return r;
}
ret:
pthread_mutex_unlock(&dcard->mutex);
return r;
}
static struct {
const char *name;
int cmd_id;
int (*handler)(ASSUAN_CONTEXT, char *line);
} ctable[] = {
{ "LISTR", 0, cmd_list_readers },
{ "LISTC", 0, cmd_list_cards },
{ "GET_OBJ", 0, cmd_get_objects },
{ "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL }
};
static int register_commands(ASSUAN_CONTEXT assuan_ctx)
{
int i, j, r;
for (i = j = 0; ctable[i].name != NULL; i++) {
int cmd_id = ctable[i].cmd_id;
if (cmd_id == 0)
cmd_id = ASSUAN_CMD_USER + j++;
r = assuan_register_command(assuan_ctx, cmd_id,
ctable[i].name, ctable[i].handler);
if (r)
return r;
}
assuan_set_hello_line(assuan_ctx, "openscd ready");
// assuan_register_reset_notify (ctx, reset_notify);
// assuan_register_option_handler (ctx, option_handler);
return 0;
}
static void * sc_thread(void *arg)
{
struct openscd_thread_arg *targ = arg;
struct openscd_context *dctx = targ->dctx;
struct sc_reader *reader = targ->reader;
struct sc_context *ctx = dctx->ctx;
const int sleep_time = 200;
int r;
free(arg);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
for (;;) {
struct openscd_card *dcard;
r = sc_detect_card_presence(reader, 0);
if (r < 0) {
sc_perror(ctx, r, "Unable to detect card presence");
return NULL;
}
pthread_testcancel();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
pthread_mutex_lock(&dctx->card_mutex);
dcard = find_card(dctx, reader, 0);
if (r == 1) {
if (dcard == NULL)
card_inserted(dctx, reader, 0);
} else {
if (dcard != NULL) {
pthread_mutex_lock(&dcard->mutex);
card_removed(dctx, dcard);
}
}
pthread_mutex_unlock(&dctx->card_mutex);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
usleep(sleep_time);
}
}
void init_cmd_stuff(struct openscd_context *dctx)
{
pthread_mutex_init(&dctx->card_mutex, NULL);
dctx->cmd_stuff_ok = 1;
dctx->card_count = 0;
dctx->thread_count = 0;
}
void cleanup_cmd_stuff(struct openscd_context *dctx)
{
int i;
if (!dctx->cmd_stuff_ok)
return;
for (i = 0; i < dctx->thread_count; i++) {
pthread_cancel(dctx->threads[i]);
pthread_join(dctx->threads[i], NULL);
}
free(dctx->threads);
pthread_mutex_destroy(&dctx->card_mutex);
for (i = 0; i < dctx->card_count; i++) {
struct openscd_card *dcard = dctx->cards + i;
if (dcard->p15card != NULL)
sc_pkcs15_unbind(dcard->p15card);
if (dcard->card != NULL)
sc_disconnect_card(dcard->card, SC_DISCONNECT_AND_RESET);
}
if (dctx->cards != NULL)
free(dctx->cards);
}
static void spawn_reader_threads(struct openscd_context *dctx)
{
int i, r, count;
if (dctx->ctx->reader_count == 0)
return;
count = dctx->ctx->reader_count;
dctx->threads = calloc(count, sizeof(pthread_t));
assert(dctx->threads != NULL);
for (i = 0; i < count; i++) {
struct openscd_thread_arg *arg;
arg = malloc(sizeof(struct openscd_thread_arg));
assert(arg != NULL);
arg->dctx = dctx;
arg->reader = dctx->ctx->reader[i];
r = pthread_create(dctx->threads + i, NULL, sc_thread, arg);
if (r) {
free(arg);
free(dctx->threads);
/* FIXME: Kill all the spawned threads */
die(1, "Unable to spawn thread: %s\n", strerror(errno));
}
}
dctx->thread_count = count;
}
void command_handler(struct openscd_context *dctx)
{
int r;
ASSUAN_CONTEXT assuan_ctx;
spawn_reader_threads(dctx);
if (dctx->socket_fd <= 0) {
int fds[2];
fds[0] = 0;
fds[1] = 1;
r = assuan_init_pipe_server(&assuan_ctx, fds);
} else
r = assuan_init_socket_server(&assuan_ctx, dctx->socket_fd);
if (r)
die(1, "Failed to initialize the server: %s\n",
assuan_strerror(r));
r = register_commands(assuan_ctx);
if (r)
die(1, "Failed to register commands with Assuan: %s\n",
assuan_strerror(r));
assuan_set_pointer(assuan_ctx, dctx);
for (;;) {
r = assuan_accept(assuan_ctx);
if (r == -1)
break;
if (r) {
error(dctx->ctx, "Assuan accept problem: %s\n", assuan_strerror(r));
break;
}
r = assuan_process(assuan_ctx);
if (r) {
error(dctx->ctx, "Assuan processing failed: %s\n", assuan_strerror(r));
continue;
}
}
assuan_deinit_server(assuan_ctx);
}

102
src/openscd/mkdtemp.c Normal file
View File

@ -0,0 +1,102 @@
/* mkdtemp.c - libc replacement function
* Copyright (C) 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG 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.
*
* GnuPG 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-1307, USA
*/
/* This is a replacement function for mkdtemp in case the platform
we're building on (like mine!) doesn't have it. */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include "../scrandom/scrandom.h"
#ifdef MKDIR_TAKES_ONE_ARG
# undef mkdir
# define mkdir(a,b) mkdir(a)
#endif
char *mkdtemp(char *template)
{
int attempts, idx, count = 0;
unsigned char *ch;
idx = strlen(template);
/* Walk backwards to count all the Xes */
while (idx > 0 && template[idx - 1] == 'X') {
count++;
idx--;
}
if (count == 0) {
errno = EINVAL;
return NULL;
}
ch = &template[idx];
/* Try 4 times to make the temp directory */
for (attempts = 0; attempts < 4; attempts++) {
int remaining = count;
char *marker = ch;
unsigned char *randombits;
idx = 0;
/* Using really random bits is probably overkill here. The
worst thing that can happen with a directory name collision
is that the function will return an error. */
randombits = malloc(4 * remaining);
assert(randombits != NULL);
assert(scrandom_get_data(randombits, 4 * remaining) ==
4 * remaining);
while (remaining > 1) {
sprintf(marker, "%02X", randombits[idx++]);
marker += 2;
remaining -= 2;
}
/* Any leftover Xes? get_random_bits rounds up to full bytes,
so this is safe. */
if (remaining > 0)
sprintf(marker, "%X", randombits[idx] & 0xF);
free(randombits);
if (mkdir(template, 0700) == 0)
break;
}
if (attempts == 4)
return NULL; /* keeps the errno from mkdir, whatever it is */
return template;
}

156
src/openscd/openscd.c Normal file
View File

@ -0,0 +1,156 @@
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <assuan.h>
#include "../libopensc/opensc.h"
#include "../libopensc/pkcs15.h"
#include <stdarg.h>
#include "openscd.h"
struct openscd_context *dctx = NULL;
int opt_pipe = 0;
void cleanup()
{
if (dctx == NULL)
return;
cleanup_cmd_stuff(dctx);
if (dctx->ctx != NULL)
sc_release_context(dctx->ctx);
if (dctx->socket_name != NULL) {
char *p;
if (dctx->socket_fd >= 0)
close(dctx->socket_fd);
unlink(dctx->socket_name);
if ((p = strrchr(dctx->socket_name, '/')) != NULL) {
*p = '\0';
rmdir(dctx->socket_name);
}
free(dctx->socket_name);
}
free(dctx);
dctx = NULL;
}
void die(int return_code, const char *errmsg, ...)
{
if (errmsg != NULL) {
va_list ap;
char *p = malloc(strlen(errmsg)+2);
strcpy(p, errmsg);
strcat(p, "\n");
va_start(ap, errmsg);
vfprintf(stderr, p, ap);
free(p);
va_end(ap);
}
cleanup();
exit(return_code);
}
void setup_socket(void)
{
int fd;
const char *socket_dir = "/tmp/openscd-XXXXXX";
const char *socket_file = "socket";
char *socket_name;
struct sockaddr_un serv_addr;
socket_name = malloc(strlen(socket_dir)+strlen(socket_file)+2);
assert(socket_name != NULL);
strcpy(socket_name, socket_dir);
if (mkdtemp(socket_name) == NULL)
die(1, "Unable to create directory '%s': %s\n",
socket_name, strerror(errno));
strcat(socket_name, "/");
strcat(socket_name, socket_file);
if (strlen(socket_name) + 1 >= sizeof(serv_addr.sun_path))
die(1, "Name of socket too long\n");
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
die(1, "Can't create socket: %s\n", strerror(errno));
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, socket_name);
if (bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) == -1) {
close(fd);
die(1, "Error binding socket to '%s': %s\n",
serv_addr.sun_path, strerror(errno));
}
if (listen(fd, 5) == -1) {
close(fd);
die(1, "listen() failed: %s\n", strerror(errno));
}
dctx->socket_name = strdup(socket_name);
dctx->socket_fd = fd;
}
void do_fork()
{
int pid;
pid = fork();
if (pid == (pid_t) -1)
die(1, "fork() failed: %s\n", strerror(errno));
if (pid) {
char *infostr;
int n = strlen(dctx->socket_name) + 40;
infostr = malloc(n);
if (snprintf(infostr, n, "OPENSCD_INFO=%s:%lu:1",
dctx->socket_name, (ulong) pid) < 0) {
kill(pid, SIGTERM);
die(1, "Something went wrong\n");
}
printf("%s; export OPENSCD_INFO;\n", infostr);
free(infostr);
free(dctx->socket_name);
dctx->socket_name = NULL;
die(0, NULL);
}
}
void init_dctx()
{
int r;
r = sc_establish_context(&dctx->ctx, "openscd");
if (r != 0)
die(1, "Unable to establish context: %s", sc_strerror(r));
init_cmd_stuff(dctx);
}
int main(int argc, char *argv[])
{
int r;
dctx = malloc(sizeof(struct openscd_context));
assert(dctx != NULL);
memset(dctx, 0, sizeof(struct openscd_context));
if (!opt_pipe) {
setup_socket();
do_fork();
}
init_dctx();
atexit(cleanup);
command_handler(dctx);
return 0;
}

42
src/openscd/openscd.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef OPENSCD_H
#include "../libopensc/opensc.h"
#include <pthread.h>
#define MAX_CARDS 4
struct openscd_context {
struct sc_context *ctx;
char *socket_name;
int socket_fd;
int cmd_stuff_ok;
struct openscd_card {
sc_card_t *card;
sc_pkcs15_card_t *p15card;
struct sc_reader *reader;
int slot_id;
int card_id;
pthread_mutex_t mutex;
} *cards;
int card_count;
int card_id_number;
pthread_mutex_t card_mutex;
pthread_t *threads;
int thread_count;
};
struct openscd_thread_arg {
struct openscd_context *dctx;
struct sc_reader *reader;
};
char *mkdtemp(char *template);
void die(int return_code, const char *errmsg, ...);
void command_handler(struct openscd_context *dctx);
void init_cmd_stuff(struct openscd_context *dctx);
void cleanup_cmd_stuff(struct openscd_context *dctx);
#endif

42
src/openscd/test.c Normal file
View File

@ -0,0 +1,42 @@
#include "../assuan/assuan.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
static AssuanError reply_cb(void *opaque, const void *buf, size_t len)
{
printf("%d\n%s\n", len, buf);
return 0;
}
int main()
{
char *infostr, *p;
char socket[150];
int r;
ASSUAN_CONTEXT ctx;
infostr = getenv("OPENSCD_INFO");
if (infostr == NULL)
return 0;
p = strchr(infostr, ':');
if (p == NULL)
return 0;
strncpy(socket, infostr, p - infostr);
socket[p - infostr] = '\0';
printf("Socket is: '%s'\n", socket);
r = assuan_socket_connect(&ctx, socket, -1);
if (r) {
fprintf(stderr, "Unable to connect: %s\n", assuan_strerror(r));
return 1;
}
r = assuan_transact(ctx, "GET_OBJ 0 400", reply_cb, NULL, NULL, NULL, NULL, NULL);
if (r) {
fprintf(stderr, "Unable to transact: %s\n", assuan_strerror(r));
return 1;
}
}