/* $Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/moira/regtape/verify.dc,v 1.4 1996/06/02 07:44:11 ghudson Exp $
 *
 * This program will verify signatures on user records in the database.
 */

#include <stdio.h>
#include <strings.h>
#include <ctype.h>
#include <sys/time.h>
#include <moira.h>
#include <moira_site.h>
#include <des.h>
#include <krb.h>
#include <krb_err.h>
#include <gdss.h>
EXEC SQL INCLUDE sqlca;


char *program;

main(argc, argv)
int argc;
char **argv;
{
    char buf[BUFSIZ], *usercheck[100], sigbuf[256], *data;
    SigInfo si;
    struct save_queue *sq;
    int status, i, wait, check, debug, fix;
    EXEC SQL BEGIN DECLARE SECTION;
    char login[10], mid[32], rawsig[256], who[257];
    int id, timestamp, sms;
    EXEC SQL END DECLARE SECTION;

    initialize_sms_error_table();
    initialize_krb_error_table();
    initialize_gdss_error_table();

    program = "sign";
    check = debug = fix = 0;

    for (i = 1; i < argc; i++) {
	if (!strcmp(argv[i], "-w"))
	  wait++;
	else if (!strcmp(argv[i], "-d"))
	  debug++;
	else if (!strcmp(argv[i], "-D"))
	  setenv("ING_SET", "set printqry");
	else if (!strcmp(argv[i], "-fix"))
	  fix++;
	else if (argv[i][0] == '-')
	  fprintf(stderr, "Usage: %s [-w] [-D] [-fix]\n", argv[0]);
	else usercheck[check++] = argv[i];
    }

    EXEC SQL CONNECT moira;

    if (fix) {
	/* Set the name of our kerberos ticket file */
	krb_set_tkt_string("/tmp/tkt_sign");
	status = 1;
	while (status) {
	    printf("Authenticating as moira.extra:\n");
	    status = krb_get_pw_in_tkt("moira", "extra", "ATHENA.MIT.EDU",
				       "krbtgt", "ATHENA.MIT.EDU",
				       DEFAULT_TKT_LIFE, 0);
	    if (status != 0)
	      com_err(program, status + krb_err_base, " in krb_get_pw_in_tkt");
	}
	com_err(program, 0, "authenticated OK");

	sms = 0;
	EXEC SQL SELECT string_id INTO :sms FROM strings 
	  WHERE string='moira.extra@ATHENA.MIT.EDU';
	if (sms == 0) {
	    com_err(program, 0, " failed to find string moira.extra@ATHENA.MIT.EDU in database");
	    dest_tkt();
	    exit(1);
	}

	sq = sq_create();
    }

    if (check == 0) {
	EXEC SQL DECLARE c CURSOR FOR
	  SELECT login, clearid, signature, string, sigdate
	  FROM users, strings
	  WHERE signature != '' and sigwho = string_id;
	EXEC SQL OPEN c;
	while (1) {
	    EXEC SQL FETCH c INTO :login, :mid, :rawsig, :who, :timestamp;
	    if (sqlca.sqlcode != 0) break;
	    sprintf(buf, "%s:%s", strtrim(login), strtrim(mid));
	    si.timestamp = timestamp;
	    si.SigInfoVersion = 0;
	    kname_parse(si.pname, si.pinst, si.prealm, strtrim(who));
	    si.rawsig = (unsigned char *) &rawsig[0];
	    status = GDSS_Recompose(&si, sigbuf);
	    if (status) {
		com_err(program, gdss2et(status), "recomposing for user %s",
			login);
		continue;
	    }
	    si.rawsig = NULL;
	    status = GDSS_Verify(buf, strlen(buf), sigbuf, &si);
	    if (status) {
		com_err(program, gdss2et(status), "verifying user %s", login);
	    }
	    if (fix && status == GDSS_E_BADSIG) {
		sq_save_data(sq, strsave(buf));
	    }
	    if (wait) {
		printf("Next");
		fflush(stdout);
		gets(buf);
	    }
	}
	if (fix) {
	    while (sq_get_data(sq, &data)) {
		strncpy(login, data, 8);
		if (index(login, ':'))
		  *index(login, ':') = 0;
	    again:
		com_err(program, 0, "fixing sig for %s", login);
		status = GDSS_Sign(data, strlen(data), sigbuf, &si);
		if (status) {
		    com_err(program, gdss2et(status), "signing data");
		    continue;
		}
		si.rawsig = (unsigned char *)rawsig;
		status = GDSS_Verify(data, strlen(data), sigbuf, &si);
		if (status) {
		    com_err(program, gdss2et(status), "verifying data");
		    continue;
		}
		if (strlen(rawsig) > 68) {
		    sleep(1);
		    goto again;
		}

		timestamp = si.timestamp;
		EXEC SQL REPEATED UPDATE users 
		  SET signature = :rawsig, sigwho = :sms, sigdate = :timestamp
		    WHERE login = :login;
		if (sqlca.sqlcode != 0) {
		    com_err(program, 0, "ingres error %d", sqlca.sqlcode);
		    dest_tkt();
		    exit(1);
		}
		EXEC SQL COMMIT WORK;
	    }
	}
    } else {
	for (i = check - 1; i >= 0; i--) {
	    strcpy(login, usercheck[i]);
	    EXEC SQL DECLARE s CURSOR FOR
	      SELECT clearid, signature, string, sigdate
	      FROM users, strings
	      WHERE signature != '' and sigwho = string_id and login = :login;
	    EXEC SQL OPEN s;
	    while (1) {
		EXEC SQL FETCH s INTO :mid, :rawsig, :who, :timestamp;
		if (sqlca.sqlcode != 0) break;
		sprintf(buf, "%s:%s", strtrim(login), strtrim(mid));
		if (debug) {
		    printf("Verifying \"%s\"\n", buf);
		}
		si.timestamp = timestamp;
		si.SigInfoVersion = 0;
		kname_parse(si.pname, si.pinst, si.prealm, strtrim(who));
		si.rawsig = (unsigned char *) &rawsig[0];
		status = GDSS_Recompose(&si, sigbuf);
		if (status) {
		    com_err(program, gdss2et(status), "recomposing for user %s", login);
		    continue;
		}
		si.rawsig = NULL;
		status = GDSS_Verify(buf, strlen(buf), sigbuf, &si);
		if (fix && status == GDSS_E_BADSIG) {
		    com_err(program, 0, "fixing signature for %s", login);
		againagain:
		    status = GDSS_Sign(buf, strlen(buf), sigbuf);
		    if (status) {
			com_err(program, gdss2et(status), "signing data");
			continue;
		    }
		    si.rawsig = (unsigned char *) rawsig;
		    status = GDSS_Verify(buf, strlen(buf), sigbuf, &si);
		    if (status) {
			com_err(program, gdss2et(status), "verifying data");
			continue;
		    }
		    if (strlen(rawsig) > 68) {
			sleep(1);
			goto againagain;
		    }

		    timestamp = si.timestamp;
		    EXEC SQL REPEATED UPDATE users 
		      SET signature = :rawsig, sigwho = :sms, sigdate = :timestamp
			WHERE login = :login;
		    if (sqlca.sqlcode != 0) {
			com_err(program, 0, "ingres error %d", sqlca.sqlcode);
			dest_tkt();
			exit(1);
		    }
		    EXEC SQL COMMIT WORK;
		} else if (status)
		  com_err(program, gdss2et(status), "verifying user %s", login);
		else {
		    com_err(program, 0, "signature verified %s", buf);
		    if (debug == 2) {
			hex_dump(sigbuf);
		    }
		}
		if (wait) {
		    printf("Next");
		    fflush(stdout);
		    gets(buf);
		}
	    }
	}
    }

    dest_tkt();
    exit(0);
}


hex_dump(p)
unsigned  char *p;
{
    printf("Size: %d\n", strlen(p));
    while (strlen(p) >= 8) {
	printf("%02x %02x %02x %02x %02x %02x %02x %02x\n",
		p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
	p += 8;
    }
    switch (strlen(p)) {
    case 7:
	printf("%02x %02x %02x %02x %02x %02x %02x\n",
		p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
	break;
    case 6:
	printf("%02x %02x %02x %02x %02x %02x\n",
		p[0], p[1], p[2], p[3], p[4], p[5]);
	break;
    case 5:
	printf("%02x %02x %02x %02x %02x\n",
		p[0], p[1], p[2], p[3], p[4]);
	break;
    case 4:
	printf("%02x %02x %02x %02x\n",
		p[0], p[1], p[2], p[3]);
	break;
    case 3:
	printf("%02x %02x %02x\n",
		p[0], p[1], p[2]);
	break;
    case 2:
	printf("%02x %02x\n",
		p[0], p[1]);
	break;
    case 1:
	printf("%02x\n",
		p[0]);
	break;
    default:
	return;
    }
}
