|
|
1.1 ! root 1: /****************************************************** ! 2: * * ! 3: * PGPSort: a utility to sort PGP 2.x keyrings * ! 4: * . * ! 5: * (c)1995 by Stale Schumacher <[email protected]> * ! 6: * Version 1.01 - 1995/09/04 * ! 7: * * ! 8: * This program is placed in the public domain and * ! 9: * may be freely distributed and modified, as long * ! 10: * as this copyright notice remains intact. The code * ! 11: * was written from scratch based on the PGP 2.x * ! 12: * format specifications, and contains no source * ! 13: * from the PGP distribution. Based on a TurboPascal * ! 14: * implementation by the same author. * ! 15: * * ! 16: * DISCLAIMER: PGPSort will always make a backup of * ! 17: * the keyring before sorting it, but the author * ! 18: * cannot take any responsibility for damage that * ! 19: * the program may cause. Use PGPSort at your own * ! 20: * risk! * ! 21: * * ! 22: * NOTE FOR PROGRAMMERS: This program was written * ! 23: * for portability, _not_ for speed! :-) * ! 24: * * ! 25: ******************************************************/ ! 26: ! 27: #include <stdlib.h> ! 28: #include <stdio.h> ! 29: #include <string.h> ! 30: #include <ctype.h> ! 31: ! 32: #define MAXKEYS 20000 /* Increase this if necessary */ ! 33: ! 34: #ifndef TRUE ! 35: #define FALSE 0 ! 36: #define TRUE !FALSE ! 37: #endif ! 38: ! 39: #ifndef SEEK_SET ! 40: #define SEEK_SET 0 ! 41: #endif ! 42: ! 43: #ifndef MIN ! 44: #define MIN(a,b) ((a)<(b)?(a):(b)) ! 45: #endif ! 46: ! 47: #ifndef FILENAME_MAX ! 48: #include <sys/param.h> ! 49: #ifdef MAXPATHLEN ! 50: #define FILENAME_MAX MAXPATHLEN ! 51: #endif ! 52: #endif ! 53: ! 54: typedef unsigned char byte; ! 55: typedef unsigned char boolean; ! 56: typedef unsigned short word16; ! 57: typedef unsigned long word32; ! 58: ! 59: #define CTB_PUBKEY 24 ! 60: #define CTB_SECKEY 20 ! 61: #define CTB_USERID 52 ! 62: #define CTB_TRUST 48 ! 63: #define CTB_SIG 8 ! 64: ! 65: #define ERR_OK 0 ! 66: #define ERR_ILLEGAL_PARAMS 1 ! 67: #define ERR_FILE_NOT_OPEN 2 ! 68: #define ERR_NOT_A_KEYRING 3 ! 69: #define ERR_COULD_NOT_BACKUP 4 ! 70: #define ERR_KEYRING_CORRUPT 5 ! 71: #define ERR_OUT_OF_MEMORY 6 ! 72: ! 73: #define SORT_NOSORT 0 ! 74: #define SORT_ON_USERID 1 ! 75: #define SORT_ON_KEYID 2 ! 76: #define SORT_ON_DATE 3 ! 77: #define SORT_ON_SIZE 4 ! 78: ! 79: #define ASCENDING TRUE ! 80: #define DESCENDING FALSE ! 81: ! 82: #define BADKEY_NO_USERID 0 ! 83: #define BADKEY_BOGUS_USERID 1 ! 84: #define BADKEY_SECRET_KEY 2 ! 85: ! 86: struct keydata { ! 87: long fpos; ! 88: word32 length, ! 89: keyid, ! 90: date; ! 91: word16 size; ! 92: char userid[26]; ! 93: boolean secret, ! 94: removed; ! 95: }; ! 96: ! 97: struct keydata *key[MAXKEYS]; ! 98: int keys = 0; ! 99: int sort_criterion; ! 100: boolean sort_order; ! 101: boolean remove_bad_keys; ! 102: ! 103: word32 get_packet_length(byte ctb, FILE *fp) ! 104: { ! 105: byte l[4] = {1,2,4,0}, ! 106: llength = l[ctb & 0x03], ! 107: i; ! 108: word32 length = 0; ! 109: ! 110: for (i=0; i<llength; i++) ! 111: length = (length << 8) + (byte) fgetc(fp); ! 112: return length; ! 113: } ! 114: ! 115: word32 read_word32(FILE *fp) ! 116: { ! 117: int i; ! 118: word32 word; ! 119: ! 120: for (i=0; i<32/8; i++) ! 121: word = (word << 8) + (byte) fgetc(fp); ! 122: return word; ! 123: } ! 124: ! 125: word16 read_word16(FILE *fp) ! 126: { ! 127: int i; ! 128: word16 word; ! 129: ! 130: for (i=0; i<16/8; i++) ! 131: word = (word << 8) + (byte) fgetc(fp); ! 132: return word; ! 133: } ! 134: ! 135: char *strupper(char *s) ! 136: { ! 137: char *p; ! 138: for (p=s; *p; p++) ! 139: *p=toupper(*p); ! 140: return s; ! 141: } ! 142: ! 143: char *strend(char *s) ! 144: { ! 145: char *p; ! 146: for (p=s; *p; p++); ! 147: return p; ! 148: } ! 149: ! 150: char *strstrip(char *s) ! 151: { ! 152: char *p; ! 153: # define stripchar(c) (c==' ' || c=='>' || c=='-') ! 154: ! 155: p=strend(s); ! 156: for (p--; p >= s && stripchar(*p); p--) ! 157: *p='\0'; ! 158: return s; ! 159: } ! 160: ! 161: char *force_extension(char *filename, char *extension) ! 162: { ! 163: char *p; ! 164: p=strrchr(filename, '.'); ! 165: if (!p) p=strend(filename); ! 166: strcpy(p, extension); ! 167: return filename; ! 168: } ! 169: ! 170: char *add_slash(char *directory) ! 171: { ! 172: char *p; ! 173: p=strend(directory); p--; ! 174: if (*p != '/' && strchr(directory, '/')) ! 175: strcat(directory, "/"); /* Unix */ ! 176: if (*p != '\\' && strchr(directory, '\\')) ! 177: strcat(directory, "\\"); /* MS-DOS */ ! 178: return directory; ! 179: } ! 180: ! 181: void prompt_for_removal(int keynr, char *userid, int cause) ! 182: { ! 183: char date[11]; ! 184: int c; ! 185: ! 186: switch (cause) { ! 187: case BADKEY_NO_USERID: ! 188: printf("The following key has no attached userID:\n"); break; ! 189: case BADKEY_BOGUS_USERID: ! 190: printf("The following key seems to have a bogus user ID:\n"); break; ! 191: case BADKEY_SECRET_KEY: ! 192: printf("The keyring contains a secret key:\n"); break; ! 193: } ! 194: if (key[keynr]->secret) ! 195: printf("sec "); ! 196: else ! 197: printf("pub "); ! 198: strftime(date,sizeof(date),"%Y/%m/%d",gmtime(&key[keynr]->date)); ! 199: printf("%4d/%8lX %s %s\n",key[keynr]->size,key[keynr]->keyid,date,userid); ! 200: printf("Remove it <y/N>? "); ! 201: fflush(stdin); c = getchar(); ! 202: key[keynr]->removed = (c=='y' || c=='Y'); ! 203: printf("\n"); ! 204: } ! 205: ! 206: char *get_username(char *userid) ! 207: { ! 208: char s[256]; ! 209: char *p = userid; ! 210: ! 211: /* Isolate name from email address, telephone number etc. */ ! 212: while (isalpha(*p) || isspace(*p) || *p=='.' || *p=='-') p++; ! 213: if (p > userid) *p='\0'; ! 214: strupper(strstrip(userid)); ! 215: ! 216: /* Derive name from email address? */ ! 217: if (*userid == '<') { ! 218: strcpy(userid, userid+1); ! 219: } ! 220: ! 221: /* Remove titles */ ! 222: p=strend(userid); ! 223: if (!strcmp(p-2, " I")) *(p-2)='\0'; ! 224: if (!strcmp(p-3, " II")) *(p-3)='\0'; ! 225: if (!strcmp(p-4, " III")) *(p-4)='\0'; ! 226: if (!strcmp(p-4, " JR.")) *(p-4)='\0'; ! 227: if (!strcmp(p-5, " M.D.")) *(p-5)='\0'; ! 228: ! 229: /* Swap first and last names */ ! 230: if ((p = strrchr(userid, ' ')) != NULL) { ! 231: strcpy(s,p+1); ! 232: *p = '\0'; ! 233: strcpy(userid, strcat(s, userid)); ! 234: } ! 235: ! 236: /* Return the user name on a form that may easily be sorted */ ! 237: return userid; ! 238: } ! 239: ! 240: int keycmp(struct keydata *key1, struct keydata *key2) ! 241: { ! 242: int c; ! 243: switch (sort_criterion) { ! 244: case SORT_ON_USERID: c = strcmp(key1->userid, key2->userid) ; break; ! 245: case SORT_ON_KEYID : c = key1->keyid < key2->keyid ? -1 : +1; break; ! 246: case SORT_ON_SIZE : c = key1->size < key2->size ? -1 : +1; break; ! 247: case SORT_ON_DATE : c = key1->date < key2->date ? -1 : +1; break; ! 248: } ! 249: if (sort_order==DESCENDING) c = -c; ! 250: return c; ! 251: } ! 252: ! 253: void swap(struct keydata *v[], int i, int j) ! 254: { ! 255: struct keydata *temp; ! 256: temp = v[i]; v[i] = v[j]; v[j] = temp; ! 257: } ! 258: ! 259: void sort_keydata(struct keydata *v[], int left, int right) ! 260: { ! 261: int i, last; ! 262: if (left >= right) return; ! 263: swap(v, left, (left+right)/2); ! 264: last = left; ! 265: for (i = left+1; i <= right; i++) ! 266: if (keycmp(v[i], v[left]) < 0) ! 267: swap(v, ++last, i); ! 268: swap(v, left, last); ! 269: sort_keydata(v, left, last-1); ! 270: sort_keydata(v, last+1, right); ! 271: } ! 272: ! 273: int sort_keyring(char *keyring) ! 274: { ! 275: FILE *ifp, ! 276: *ofp; ! 277: long count, ! 278: fpos = 0L, ! 279: ctbpos = 0L; ! 280: byte ctb; ! 281: word32 packet_length; ! 282: char userid[256], ! 283: bakring[FILENAME_MAX]; ! 284: boolean is_pubring, ! 285: first_userid = FALSE; ! 286: byte buf[256]; ! 287: int i, ! 288: status = ERR_OK; ! 289: ! 290: # define error(s) {status = s; goto end;} ! 291: ! 292: /* Read through the whole keyring and gather keydata */ ! 293: if (!(ifp = fopen(keyring,"rb"))) ! 294: return ERR_FILE_NOT_OPEN; ! 295: count = fread(&ctb, 1, 1, ifp); ! 296: if ((ctb & 60) == CTB_PUBKEY) ! 297: is_pubring = TRUE; ! 298: else if ((ctb & 60) == CTB_SECKEY) ! 299: is_pubring = FALSE; ! 300: else ! 301: error(ERR_NOT_A_KEYRING); ! 302: while (count > 0) { ! 303: if (!(ctb & 0x80)) ! 304: error(ERR_KEYRING_CORRUPT); ! 305: packet_length = get_packet_length(ctb, ifp); ! 306: fpos = ftell(ifp); ! 307: ctb = (ctb & 60); ! 308: switch (ctb) { ! 309: case CTB_PUBKEY: ! 310: case CTB_SECKEY: ! 311: if (first_userid && remove_bad_keys && (!key[keys-1]->removed)) ! 312: prompt_for_removal(keys-1,"",BADKEY_NO_USERID); ! 313: if (keys == MAXKEYS) ! 314: error(ERR_OUT_OF_MEMORY); ! 315: if (!(key[keys] = malloc(sizeof(struct keydata)))) ! 316: error(ERR_OUT_OF_MEMORY); ! 317: if (keys>0) key[keys-1]->length = ctbpos - key[keys-1]->fpos; ! 318: key[keys]->fpos = ctbpos; ! 319: key[keys]->length = packet_length; ! 320: fseek(ifp, fpos+1, SEEK_SET); key[keys]->date = read_word32(ifp); ! 321: fseek(ifp, fpos+8, SEEK_SET); key[keys]->size = read_word16(ifp); ! 322: fseek(ifp, fpos+6+(key[keys]->size+7)/8, SEEK_SET); ! 323: key[keys]->keyid = read_word32(ifp); ! 324: key[keys]->removed = FALSE; ! 325: key[keys]->secret = (ctb==CTB_SECKEY); ! 326: first_userid = TRUE; ! 327: keys++; ! 328: break; ! 329: case CTB_USERID: ! 330: fread(&userid, packet_length, 1, ifp); ! 331: userid[packet_length]='\0'; ! 332: if (remove_bad_keys && (!key[keys-1]->removed)) { ! 333: if (strstr(userid,"FUCK") || strstr(userid,"DICK") || ! 334: strstr(userid,"SHIT") || strstr(userid,"BEGIN") || ! 335: strstr(userid,"***") || strstr(userid,"@whitehouse.gov") || ! 336: strlen(userid) > 150) ! 337: prompt_for_removal(keys-1,userid,BADKEY_BOGUS_USERID); ! 338: } ! 339: if (first_userid) { ! 340: if (key[keys-1]->secret && remove_bad_keys && (!key[keys-1]->removed) ! 341: && is_pubring) ! 342: prompt_for_removal(keys-1,userid,BADKEY_SECRET_KEY); ! 343: strncpy(key[keys-1]->userid, get_username(userid), ! 344: sizeof(key[keys-1]->userid)); ! 345: first_userid = FALSE; ! 346: } ! 347: case CTB_TRUST: ! 348: case CTB_SIG: ! 349: break; ! 350: default: ! 351: error(ERR_NOT_A_KEYRING); ! 352: } ! 353: fseek(ifp, ctbpos = fpos += packet_length, SEEK_SET); ! 354: count = fread(&ctb, 1, 1, ifp); ! 355: } ! 356: key[keys-1]->length = ctbpos - key[keys-1]->fpos; ! 357: fclose(ifp); ! 358: ! 359: /* Sort keydata in main memory */ ! 360: if (sort_criterion != SORT_NOSORT) ! 361: sort_keydata(key,0,keys-1); ! 362: ! 363: /* Backup the unsorted keyring in case something goes wrong */ ! 364: strcpy(bakring,keyring); ! 365: force_extension(bakring,".bak"); ! 366: remove(bakring); ! 367: if (rename(keyring,bakring)) ! 368: error(ERR_COULD_NOT_BACKUP); ! 369: ! 370: /* Copy the keys from old to new keyring in sorted order */ ! 371: if (!(ifp=fopen(bakring,"rb"))) ! 372: error(ERR_COULD_NOT_BACKUP); ! 373: if (!(ofp=fopen(keyring,"wb"))) ! 374: error(ERR_COULD_NOT_BACKUP); ! 375: for (i=0; i<keys; i++) ! 376: if (!key[i]->removed) { ! 377: fseek(ifp,key[i]->fpos, SEEK_SET); ! 378: while (key[i]->length > 0) { ! 379: size_t bytes = MIN(key[i]->length, sizeof(buf)); ! 380: fread(&buf, bytes, 1, ifp); ! 381: fwrite(&buf, bytes, 1, ofp); ! 382: key[i]->length -= bytes; ! 383: } ! 384: } ! 385: fclose(ofp); ! 386: ! 387: end: ! 388: /* Remember to cleanup after us */ ! 389: fclose(ifp); ! 390: for (i = 0; i < keys; i++) ! 391: free(key[i]); ! 392: return status; ! 393: } ! 394: ! 395: void show_usage() ! 396: { ! 397: fprintf(stderr, "\nPGPSort v1.01 (c) 1995 [email protected]\n\n"); ! 398: fprintf(stderr, "Synopsis: Sorts PGP 2.x keyrings\n\n"); ! 399: fprintf(stderr, "Usage : pgpsort +u[r] [keyring] - sort on user ID\n"); ! 400: fprintf(stderr, " pgpsort +k[r] [keyring] - sort on key ID\n"); ! 401: fprintf(stderr, " pgpsort +s[r] [keyring] - sort on key size\n"); ! 402: fprintf(stderr, " pgpsort +d[r] [keyring] - sort on date of creation\n"); ! 403: fprintf(stderr, " pgpsort -r [keyring] - remove keys (no sorting)\n\n"); ! 404: fprintf(stderr, " Use 'r' to remove bad keys\n"); ! 405: fprintf(stderr, " Use '-' instead of '+' to sort in descending order\n\n"); ! 406: exit(ERR_ILLEGAL_PARAMS); ! 407: } ! 408: ! 409: int main(int argc, char *argv[]) ! 410: { ! 411: char *sort_option; ! 412: char filename[FILENAME_MAX]; ! 413: ! 414: /* Parse command line options */ ! 415: if (argc==2 || argc==3) { ! 416: sort_option = argv[1]; ! 417: if (argc==3) ! 418: strcpy(filename, argv[2]); ! 419: else { ! 420: printf("No filename given, assuming default keyring.\n"); ! 421: if (getenv("PGPPATH")) ! 422: add_slash(strcpy(filename, getenv("PGPPATH"))); ! 423: else if (getenv("HOME") && strchr(getenv("HOME"), '/')) ! 424: strcat(add_slash(strcpy(filename, getenv("HOME"))), ".pgp/"); ! 425: else ! 426: filename[0]='\0'; ! 427: strcat(filename, "pubring.pgp"); ! 428: } ! 429: } else ! 430: show_usage(); ! 431: if (strlen(sort_option)==2 || strlen(sort_option)==3) { ! 432: switch (sort_option[0]) { ! 433: case '+': sort_order=ASCENDING; break; ! 434: case '-': sort_order=DESCENDING; break; ! 435: default : show_usage(); ! 436: } ! 437: if (strlen(sort_option)==2) ! 438: remove_bad_keys = FALSE; ! 439: else if (sort_option[1]!='r' && sort_option[2]=='r') ! 440: remove_bad_keys = TRUE; ! 441: else ! 442: show_usage(); ! 443: switch (sort_option[1]) { ! 444: case 'u': sort_criterion=SORT_ON_USERID; break; ! 445: case 'k': sort_criterion=SORT_ON_KEYID; break; ! 446: case 's': sort_criterion=SORT_ON_SIZE; break; ! 447: case 'd': sort_criterion=SORT_ON_DATE; break; ! 448: case 'r': sort_criterion=SORT_NOSORT; ! 449: remove_bad_keys=TRUE; break; ! 450: default : show_usage(); ! 451: } ! 452: } else ! 453: show_usage(); ! 454: ! 455: /* OK, attempt to sort the keyring */ ! 456: switch (sort_keyring(filename)) { ! 457: case ERR_OK: ! 458: printf("Keyring '%s' ", filename); ! 459: switch (sort_criterion) { ! 460: case SORT_NOSORT : printf("processed.\n"); break; ! 461: case SORT_ON_USERID: printf("sorted on user ID.\n"); break; ! 462: case SORT_ON_KEYID : printf("sorted on key ID.\n"); break; ! 463: case SORT_ON_SIZE : printf("sorted on key size.\n"); break; ! 464: case SORT_ON_DATE : printf("sorted on date.\n"); ! 465: } ! 466: return ERR_OK; ! 467: case ERR_FILE_NOT_OPEN: ! 468: fprintf(stderr, "Could not open keyring file '%s'.\n", filename); ! 469: return ERR_FILE_NOT_OPEN; ! 470: case ERR_NOT_A_KEYRING: ! 471: fprintf(stderr, "File '%s' is not a PGP 2.x keyring.\n", filename); ! 472: return ERR_NOT_A_KEYRING; ! 473: case ERR_COULD_NOT_BACKUP: ! 474: fprintf(stderr, "Could not create backup file, keyring not sorted.\n"); ! 475: return ERR_COULD_NOT_BACKUP; ! 476: case ERR_KEYRING_CORRUPT: ! 477: fprintf(stderr, "Keyring '%s' is corrupt, cannot sort it.\n", filename); ! 478: return ERR_KEYRING_CORRUPT; ! 479: case ERR_OUT_OF_MEMORY: ! 480: fprintf(stderr, "Out of memory: keyring '%s' is too big to sort.\n", filename); ! 481: return ERR_OUT_OF_MEMORY; ! 482: } ! 483: ! 484: return 0; /* Just to please some compilers */ ! 485: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.