/* $Id$ * * This program will verify signatures on user records in the database. * * Copyright (C) 1993-1998 by the Massachusetts Institute of Technology * For copying and distribution information, please see the file * . */ #include #include #include #include #include #include #include #include #include EXEC SQL INCLUDE sqlca; RCSID("$Header$"); void hex_dump(unsigned char *p); char *program; int main(int argc, char **argv) { char buf[BUFSIZ], *usercheck[100], sigbuf[256], *data, *db = "moira"; 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]; EXEC SQL VAR rawsig IS STRING(256); int 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], "-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 :db IDENTIFIED BY :db; 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 != CHR(0) and sigwho = string_id; EXEC SQL OPEN c; while (1) { EXEC SQL FETCH c INTO :login, :mid, :rawsig, :who, :timestamp; if (sqlca.sqlcode) 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, strdup(buf)); if (wait) { printf("Next"); fflush(stdout); gets(buf); } } if (fix) { while (sq_get_data(sq, &data)) { strncpy(login, data, 8); if (strchr(login, ':')) *strchr(login, ':') = '\0'; again: com_err(program, 0, "fixing sig for %s", login); status = GDSS_Sign(data, strlen(data), sigbuf); 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 UPDATE users SET signature = :rawsig, sigwho = :sms, sigdate = :timestamp WHERE login = :login; if (sqlca.sqlcode) { com_err(program, 0, "dbms 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 sigwho = string_id and login = :login; EXEC SQL OPEN s; while (1) { EXEC SQL FETCH s INTO :mid, :rawsig, :who, :timestamp; if (sqlca.sqlcode) 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 UPDATE users SET signature = :rawsig, sigwho = :sms, sigdate = :timestamp WHERE login = :login; if (sqlca.sqlcode != 0) { com_err(program, 0, "dbms 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); } void hex_dump(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; } }