/* 
 * cryptint.c: interface between kernel module and crypto engine
 * Copyright (C) 2002 Axel Burri <axel@purrly.ch>
 *
 * 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-1307, USA.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
//#include <sys/stat.h>
#include "cryptint_kernel.h"
#include "cryptint_user.h"

#include "debug.h"


char *proc_fn = NULL;
cryptint_sign_cb sign_cb = NULL;
cryptint_verify_cb verify_cb = NULL;

#if 0
void readtest(char *fn) {
    int len;
    int fd;
    struct cryptint_msg_t msg;

    fd = open(fn, O_RDONLY);
    if(fd < 0) {
	fprintf(stderr, "unable to open file: %s\n", fn);
	exit(-1);
    }

    len = read(fd, &msg, sizeof(struct cryptint_msg_t));
    DEBUGP("message: read=%i, type=%i\n", len, msg.type);
    close(fd);
}


void writetest(char *fn) {
    int len;
    int size;
    int fd;
    struct cryptint_msg_t msg;

    fd = open(fn, O_WRONLY);
    if(fd < 0) {
	fprintf(stderr, "unable to open file: %s\n", fn);
	exit(-1);
    }

    msg.type = 123;
    strcpy(msg.data, "1234567890");

//    size = sizeof(struct cryptint_msg_header_t) + msg.header.length;
    len = write(fd, &msg, size);
    DEBUGP("message: size=%i, written=%i, type=%i, len=%i\n", size, len, msg.header.type, msg.header.length);
    close(fd);
}
#endif


/*
 * init the crypto interface.
 * using callback functions
 */
int cryptint_init(char *filename, cryptint_sign_cb sign, cryptint_verify_cb verify) {
    if(filename) {
	proc_fn = filename;
    } else {
	DEBUGP("cryptint_init: error: filename=NULL\n");
	return -1;
    }
    
    if(sign && verify) {
	sign_cb = sign;
	verify_cb = verify;
    } else {
	DEBUGP("cryptint_init: error: callback functions not defined\n");
	return -1;
    }
	

    return 0;
}




void write_msg(void *msg, size_t size) {
    int len;
    int fd;

    fd = open(proc_fn, O_WRONLY);
    if(fd < 0) {
	fprintf(stderr, "unable to open file: %s\n", proc_fn);
	exit(-1);
    }

    len = write(fd, msg, size);
    DEBUGP("write message: size=%i, written=%i\n", size, len);
    close(fd);
}



int sign(struct cryptint_msg_qos_sign_t *msg) {
    struct cryptint_msg_qos_sign_rep_t answer;

    DEBUGP("sign: sigtype=%i, addr=%x\n", msg->sig_type, msg->taddr);

    answer.type = CRYPTINT_MSG_QOS_SIGN_REP;
    answer.taddr = msg->taddr;
    sign_cb(msg->plain, CRYPTINT_QOS_PLAINTEXT_SIZE, answer.sig, MAX_SIG_LEN, &answer.sig_length);
    memcpy(answer.plain, msg->plain, CRYPTINT_QOS_PLAINTEXT_SIZE);

    /* TODO: shorten! */
    write_msg(&answer, sizeof(struct cryptint_msg_qos_sign_rep_t));
    return 0;
}

/*
 * verify qos packet and send back {qos, trust}
 */
int qos_verify(struct cryptint_msg_qos_verify_t *msg) {
    struct cryptint_msg_qos_trust_t answer;
    int trust;

/* TODO: switch sig_type */

    DEBUGP("qos_verify: sigtype=%i, qos=%i, sig_size=%i, addr=%x\n", msg->sig_type, msg->qos, msg->sig_length, msg->addr);
#if 0
    {
	FILE *f = fopen("out.plain", "w");
	fwrite(msg->plain, 1, CRYPTINT_QOS_PLAINTEXT_SIZE, f);
	fclose(f);
    }
    {
	FILE *f = fopen("out.sig", "w");
	fwrite(msg->sig, 1, msg->sig_length, f);
	fclose(f);
    }
#endif

    trust = verify_cb(msg->plain,
		      msg->sig, 
		      CRYPTINT_QOS_PLAINTEXT_SIZE, 
		      msg->sig_length);

    answer.type = CRYPTINT_MSG_QOS_TRUST;
    answer.sig_type = msg->sig_type;
    answer.addr = msg->addr;
    answer.qos = msg->qos;
    answer.trust = trust;

    DEBUGP("qos_verify: addr=%x, QoS=%i, trust=%i\n", answer.addr, answer.qos, answer.trust);

    write_msg(&answer, sizeof(struct cryptint_msg_qos_trust_t));

    return 0;
}



void cryptint_listen() {
    int len;
    int fd;
    struct cryptint_msg_t msg;

    DEBUGP("cryptint: listening on %s\n", proc_fn);

    while(1) {
	fd = open(proc_fn, O_RDONLY);
	if(fd < 0) {
	    fprintf(stderr, "unable to open file: %s\n", proc_fn);
	    exit(-1);
	}

	len = read(fd, &msg, sizeof(struct cryptint_msg_t));
	DEBUGP("read message: size=%i, type=%i\n", len, msg.type);
	close(fd);

	/* decide what to do with message */
	/* TODO: call different handler (ssl/gpg) dependant on sigtype */
	switch(msg.type) {
	case CRYPTINT_MSG_QOS_SIGN:
	    sign((struct cryptint_msg_qos_sign_t *)(&msg));
	    break;
	case CRYPTINT_MSG_QOS_VERIFY:
	    qos_verify((struct cryptint_msg_qos_verify_t *)(&msg));
	    break;
	default:
	    DEBUGP("cryptint_listen: unknown message type %i\n", msg.type);
	}
    }
}
