Annotation of pgp/contrib/pgpsort/pgpsort.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.