URI:
       trem.c - mixmaster - mixmaster 3.0 patched for libressl
  HTML git clone git://parazyd.org/mixmaster.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       trem.c (18892B)
       ---
            1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
            2 
            3    Mixmaster may be redistributed and modified under certain conditions.
            4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
            5    ANY KIND, either express or implied. See the file COPYRIGHT for
            6    details.
            7 
            8    Process remailer messages
            9    $Id: rem.c 934 2006-06-24 13:40:39Z rabbi $ */
           10 
           11 
           12 #include "mix3.h"
           13 #include <stdlib.h>
           14 #include <string.h>
           15 #include <time.h>
           16 #include <ctype.h>
           17 #include <sys/types.h>
           18 #include <sys/stat.h>
           19 #ifdef POSIX
           20 #include <unistd.h>
           21 #else /* end of POSIX */
           22 #include <io.h>
           23 #endif /* else if not POSIX */
           24 #ifndef _MSC
           25 #include <dirent.h>
           26 #endif /* not _MSC */
           27 #include <assert.h>
           28 
           29 int blockrequest(BUFFER *message);
           30 int create_dummy_mailin();
           31 
           32 #define REQUESTHELP  100
           33 #define REQUESTSTATS 101
           34 #define REQUESTKEY   200
           35 #define REQUESTCONF  201
           36 #define REQUESTOPKEY 202
           37 #define REQUESTOTHER 203
           38 #define BLOCKREQUEST 666
           39 #define DISABLED      99
           40 
           41 #define CPUNKMSG 1
           42 #define MIXMSG 2
           43 
           44 
           45 /** \brief get replies for additional information requests
           46  *
           47  * \param reply The buffer to store the reply in
           48  * \param file        The file or name of information a user requested
           49  * \returns 0 on success; -1 if a ressource has a valid name
           50  *     but doesn't exist; 1 if the ressource name isn't valid.
           51  * 
           52  * This function returns additional information that a
           53  * user may have requested.  One obvious example is help files
           54  * in different languages.  We don't want to hack the source every
           55  * time we or somebody else adds a new language.
           56  *
           57  * Therefore we add a new directory where the operator may
           58  * just create new files (say "remailer-help-de"). If a user
           59  * requests that using this (file|ressource) name in the
           60  * subject line we respond by sending it.
           61  *
           62  * Perhaps we should build something that returns an index of
           63  * available files (FIXME if done).
           64  *
           65  * A ressource name needs to start with the string "remailer-"
           66  * and must only consist of alphanumerical characters and dashes.
           67  * Checking is done by this function and an error returned
           68  * if this is violated.
           69  */
           70 int get_otherrequests_reply(BUFFER *reply, BUFFER *filename)
           71 {
           72   FILE *f = NULL;
           73   int c;
           74   int err;
           75   BUFFER *path;
           76 
           77   path = buf_new();
           78 
           79   assert(filename);
           80   assert(reply);
           81 
           82   buf_rewind(filename);
           83   err = bufileft(filename, "remailer-");
           84   if (! err) {
           85     err = 1;
           86     goto end;
           87   };
           88 
           89   while ((c = buf_getc(filename)) != -1) {
           90     int ok = (c >= 'A' && c <= 'Z') ||
           91              (c >= 'a' && c <= 'z') ||
           92              (c >= '0' && c <= '9') ||
           93              c == '-';
           94     if (!ok) {
           95       err = 1;
           96       goto end;
           97     };
           98   };
           99   buf_rewind(filename);
          100 
          101   buf_appends(path, REQUESTDIR);
          102   buf_appends(path, "/");
          103   buf_cat(path, filename);
          104 
          105   f = mix_openfile(path->data, "r");
          106   if (f == NULL) {
          107     err = -1;
          108     goto end;
          109   };
          110 
          111   buf_read(reply, f);
          112   err = 0;
          113 end:
          114   if (f)
          115     fclose(f);
          116   buf_free(path);
          117   return (err);
          118 }
          119 
          120 int mix_decrypt(BUFFER *message)
          121 {
          122   int type = 0;
          123   BUFFER *field, *content;
          124   BUFFER *to, *subject, *replyto, *reply;
          125   BUFFER *otherrequest;
          126   FILE *f;
          127   BUFFER *block;
          128   int err = 0;
          129   int quoted_printable = 0;     /* is this message quoted printable encoded */
          130 
          131   mix_init(NULL);
          132   field = buf_new();
          133   content = buf_new();
          134   to = buf_new();
          135   replyto = buf_new();
          136   reply = buf_new();
          137   block = buf_new();
          138   subject = buf_new();
          139   otherrequest = buf_new();
          140   buf_sets(subject, "Subject: Re: your mail");
          141 
          142   buf_rewind(message);
          143 
          144   f = mix_openfile(SOURCEBLOCK, "r");
          145   if (f != NULL) {
          146     buf_read(block, f);
          147     fclose(f);
          148   }
          149   for (;;) {
          150     err = buf_getheader(message, field, content);
          151     if (err == 1) {
          152       /* "::" marks for additional header lines */
          153       while (buf_lookahead(message, field) == 1)
          154         buf_getheader(message, field, content);
          155       if (isline(field, HDRMARK))
          156         continue;
          157       else
          158         goto hdrend;
          159     }
          160     if (err == -1)
          161       goto hdrend;
          162 
          163     if ((bufieq(field, "from") || bufieq(field, "sender") || bufieq(field,"received")) &&
          164        doblock(content, block, 1) != 0)
          165       goto end;
          166 
          167     if (bufieq(field, "to"))
          168       buf_cat(to, content);
          169     else if (bufieq(field, "from") && replyto->length == 0)
          170       /* reply to From address if no Reply-To header present */
          171       buf_set(replyto, content);
          172     else if (bufieq(field, "reply-to"))
          173       buf_set(replyto, content);
          174     else if (MIX && bufieq(field, "remailer-type") &&
          175              bufileft(content, "mixmaster"))
          176       type = MIXMSG;
          177     else if (bufieq(field, "subject")) {
          178       if (bufieq(content, "help") || bufieq(content, "remailer-help"))
          179         type = REQUESTHELP;
          180       else if (bufieq(content, "remailer-stats"))
          181         type = REQUESTSTATS;
          182       else if (bufieq(content, "remailer-key"))
          183         type = REQUESTKEY;
          184       else if (bufieq(content, "remailer-adminkey"))
          185         type = REQUESTOPKEY;
          186       else if (bufieq(content, "remailer-conf"))
          187         type = REQUESTCONF;
          188       else if (bufileft(content, "remailer-")) {
          189         type = REQUESTOTHER;
          190         buf_set(otherrequest, content);
          191       } else if (bufileft(content, "destination-block"))
          192         type = BLOCKREQUEST;
          193       else {
          194         buf_sets(subject, "Subject: ");
          195         if (!bufileft(content, "re:"))
          196           buf_appends(subject, "Re: ");
          197         buf_cat(subject, content);
          198       }
          199     } else if (bufieq(field, "test-to") || bufieq(field, "encrypted") ||
          200                bufieq(field, "anon-to") ||
          201                bufieq(field, "request-remailing-to") ||
          202                bufieq(field, "remail-to") || bufieq(field, "anon-post-to") ||
          203                bufieq(field, "post-to") || bufieq(field, "anon-send-to") ||
          204                bufieq(field, "send-to") || bufieq(field, "remix-to") ||
          205                bufieq(field, "encrypt-to"))
          206       type = CPUNKMSG;
          207     else if (bufieq(field, "content-transfer-encoding")
          208              && bufieq(content, "quoted-printable")) {
          209       quoted_printable = 1;
          210     }
          211 
          212   }
          213 hdrend:
          214   if (quoted_printable)
          215     qp_decode_message(message);
          216 
          217   if (type > 0 && REMAIL == 0)
          218     type = DISABLED;
          219   switch (type) {
          220   case REQUESTHELP:
          221     if (sendinfofile(HELPFILE, NULL, replyto, NULL) == -1)
          222       errlog(WARNING, "No help file available.\n");
          223     break;
          224   case REQUESTKEY:
          225     err = key(reply);
          226     if (err == 0)
          227       err = sendmail(reply, REMAILERNAME, replyto);
          228     break;
          229   case REQUESTOPKEY:
          230     err = adminkey(reply);
          231     if (err == 0)
          232       err = sendmail(reply, REMAILERNAME, replyto);
          233     break;
          234   case REQUESTSTATS:
          235     err = stats(reply);
          236     if (err == 0)
          237       err = sendmail(reply, REMAILERNAME, replyto);
          238     break;
          239   case REQUESTCONF:
          240     err = conf(reply);
          241     if (err == 0)
          242       err = sendmail(reply, REMAILERNAME, replyto);
          243     break;
          244   case REQUESTOTHER:
          245     err = get_otherrequests_reply(reply, otherrequest);
          246     if (err == 0)
          247       err = sendmail(reply, REMAILERNAME, replyto);
          248     break;
          249   case CPUNKMSG:
          250     err = t1_decrypt(message);
          251     if (err != 0) {
          252       errlog(LOG, "Invalid type 1 message from %b\n", replyto);
          253       sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
          254       logmail(err == -2 ? MAILUSAGE : MAILERROR, message);
          255     } else
          256       create_dummy_mailin();
          257     break;
          258   case MIXMSG:
          259     err = t2_decrypt(message);
          260     if (err == -1) {
          261       errlog(LOG, "Invalid type 2 message from %b\n", replyto);
          262       sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
          263       logmail(MAILERROR, message);
          264     } else
          265       create_dummy_mailin();
          266     break;
          267   case BLOCKREQUEST:
          268     blockrequest(message);
          269     /* Already wrote a log entry in blockrequest() */
          270     logmail(MAILBLOCK, message);
          271     break;
          272   case DISABLED:
          273     errlog(ERRORMSG, "Remailer is disabled.\n");
          274     buf_sets(reply, "Subject: remailer error\n\nThe remailer is disabled.\n");
          275     sendmail(reply, REMAILERNAME, replyto);
          276     logmail(MAILERROR, message);
          277     break;
          278   default:
          279     if (strifind
          280         (replyto->data, "mailer-daemon")) {
          281       errlog(LOG, "Bounce mail from %b\n", replyto);
          282       logmail(MAILBOUNCE, message);
          283     } else if (bufifind(to, REMAILERADDR) && blockrequest(message)) {
          284       /* Already wrote a log entry in blockrequest() */
          285       logmail(MAILBLOCK, message);
          286     } else if (bufifind(to, REMAILERADDR)) {
          287       errlog(LOG, "Non-remailer message from %b\n", replyto);
          288       if (AUTOREPLY)
          289         sendinfofile(USAGEFILE, USAGELOG, replyto, NULL);
          290       logmail(MAILUSAGE, message);
          291     } else if (bufifind(to, COMPLAINTS)) {
          292       errlog(WARNING, "Abuse complaint from %b\n", replyto);
          293       if (AUTOREPLY)
          294         sendinfofile(ABUSEFILE, NULL, replyto, subject);
          295       logmail(MAILABUSE, message);
          296     } else if (ANONADDR[0] && bufifind(to, ANONADDR)) {
          297       errlog(LOG, "Reply to anonymous message from %b\n", replyto);
          298       if (AUTOREPLY)
          299         sendinfofile(REPLYFILE, NULL, replyto, subject);
          300       logmail(MAILANON, message);
          301     } else {
          302       errlog(DEBUGINFO, "Mail from %b\n", replyto);
          303       logmail(MAILBOX, message);
          304     }
          305     err = 1;
          306   }
          307 end:
          308   buf_free(field);
          309   buf_free(content);
          310   buf_free(to);
          311   buf_free(replyto);
          312   buf_free(reply);
          313   buf_free(block);
          314   buf_free(subject);
          315   buf_free(otherrequest);
          316   return (err);
          317 }
          318 
          319 int create_dummy_mailin()
          320 {
          321   while (rnd_number(100) < INDUMMYP) {
          322     errlog(DEBUGINFO, "Generating dummy message with incoming mail.\n");
          323     if (mix_encrypt(MSG_NULL, NULL, NULL, 1, NULL) == -1)
          324       return -1;
          325   }
          326   return 0;
          327 }
          328 
          329 int t2_decrypt(BUFFER *in)
          330 {
          331   int err = 0;
          332   BUFFER *msg;
          333 
          334   msg = buf_new();
          335   do {
          336     err = mix_dearmor(in, msg);
          337     if (err != -1) {
          338       err = mix2_decrypt(msg);
          339     }
          340   }
          341   while (in->ptr + 1000 < in->length);        /* accept several packets in one message */
          342 
          343   buf_free(msg);
          344   return (err);
          345 }
          346 
          347 int mix_pool(BUFFER *msg, int type, long latent)
          348 {
          349   char path[PATHMAX], pathtmp[PATHMAX];
          350   FILE *f;
          351   int err = -1;
          352 
          353   f = pool_new(latent > 0 ? "lat" : "msg", pathtmp, path);
          354   if (f != NULL) {
          355     if (latent > 0)
          356       fprintf(f, "%d %ld\n", type, latent + time(NULL));
          357     else
          358       fprintf(f, "%d 0\n", type);
          359     err = buf_write_sync(msg, f);
          360   }
          361   if (err == 0) {
          362     rename(pathtmp, path);
          363     errlog(DEBUGINFO, "Added message to pool.\n");
          364   }
          365   return (err);
          366 }
          367 
          368 int pool_packetfile(char *fname, BUFFER *mid, int packetnum)
          369      /* create a filename */
          370 {
          371 #ifdef SHORTNAMES
          372   sprintf(fname, "%s%cp%02x%02x%02x%01x.%02x", POOLDIR, DIRSEP,
          373           mid->data[0], mid->data[1], mid->data[2], mid->data[3] & 15,
          374           packetnum);
          375 #else /* end of SHORTNAMES */
          376   sprintf(fname, "%s%cp%02x%02x%02x%02x%02x%02x%01x", POOLDIR, DIRSEP,
          377           packetnum, mid->data[0], mid->data[1], mid->data[2], mid->data[3],
          378           mid->data[4], mid->data[5] & 15);
          379 #endif /* else if not SHORTNAMES */
          380   return (0);
          381 }
          382 
          383 void pool_packetexp(void)
          384 {
          385   char *path;
          386   DIR *d;
          387   struct dirent *e;
          388   struct stat sb;
          389 
          390   d = opendir(POOLDIR);
          391   errlog(DEBUGINFO, "Checking for old parts.\n");
          392   if (d != NULL)
          393     for (;;) {
          394       e = readdir(d);
          395       if (e == NULL)
          396         break;
          397       if (e->d_name[0] == 'p' || e->d_name[0] == 'e' || e->d_name[0] == 't') {
          398         path=malloc(strlen(POOLDIR)+strlen(e->d_name)+strlen(DIRSEPSTR)+1);
          399         if (path) {
          400          strcpy(path, POOLDIR);
          401           strcat(path, DIRSEPSTR);
          402           strcat(path, e->d_name);
          403           if (stat(path, &sb) == 0 && time(NULL) - sb.st_mtime > PACKETEXP) {
          404              if (e->d_name[0] == 'p') {
          405                 errlog(NOTICE, "Expiring incomplete partial message %s.\n",
          406                 e->d_name);
          407              }
          408              else if (e->d_name[0] == 'e') {
          409                 errlog(NOTICE, "Expiring old error message %s.\n",
          410                 e->d_name);
          411              }
          412              else if (e->d_name[0] == 't') {
          413                 errlog(NOTICE, "Expiring moldy temporary message %s.\n",
          414                 e->d_name);
          415              }
          416              unlink(path);
          417           }
          418         free(path);
          419         }
          420       }
          421     }
          422   closedir(d);
          423 }
          424 
          425 void logmail(char *mailbox, BUFFER *message)
          426 {
          427   time_t t;
          428   struct tm *tc;
          429   char line[LINELEN];
          430 
          431   /* mailbox is "|program", "user@host", "stdout", "Maildir/" or "filename" */
          432   buf_rewind(message);
          433   if (mailbox[0] == '\0')        /* default action */
          434     mailbox = MAILBOX;
          435   if (strieq(mailbox, "stdout"))
          436     buf_write(message, stdout);
          437   else if (mailbox[0] == '|') {
          438     FILE *p;
          439 
          440     errlog(DEBUGINFO, "Piping message to %s.\n", mailbox + 1);
          441     p = openpipe(mailbox + 1);
          442     if (p != NULL) {
          443       buf_write(message, p);
          444       closepipe(p);
          445     }
          446   } else if (strchr(mailbox, '@')) {
          447     BUFFER *field, *content;
          448 
          449     field = buf_new();
          450     content = buf_new();
          451     while (buf_getheader(message, field, content) == 0)
          452       if (bufieq(field, "x-loop") && bufifind(content, REMAILERADDR)) {
          453         errlog(WARNING, "Loop detected! Message not sent to %s.\n", mailbox);
          454         goto isloop;
          455       }
          456     buf_sets(content, mailbox);
          457     sendmail_loop(message, NULL, content);
          458   isloop:
          459     buf_free(field);
          460     buf_free(content);
          461   } else if (mailbox[strlen(mailbox)-1] == DIRSEP) {
          462     /* the user is requesting Maildir delivery */
          463     if(maildirWrite(mailbox, message, 1) != 0) {
          464       errlog(ERRORMSG, "Can't write to maildir %s\n", mailbox);
          465       return;
          466     }
          467   } else {
          468     FILE *mbox;
          469 
          470     mbox = mix_openfile(mailbox, "a");
          471     if (mbox == NULL) {
          472       errlog(ERRORMSG, "Can't write to mail folder %s\n", mailbox);
          473       return;
          474     }
          475     lock(mbox);
          476     if (!bufileft(message, "From ")) {
          477       t = time(NULL);
          478       tc = localtime(&t);
          479       strftime(line, LINELEN, "From Mixmaster %a %b %d %H:%M:%S %Y\n", tc);
          480       fprintf(mbox, line);
          481     }
          482     buf_write(message, mbox);
          483     fprintf(mbox, "\n\n");
          484     unlock(mbox);
          485     fclose(mbox);
          486   }
          487 }
          488 
          489 int blockrequest(BUFFER *message)
          490 {
          491   int request = 0, num, i;
          492   BUFFER *from, *line, *field, *content, *addr, *remailer_addr, *copy_addr;
          493   REMAILER remailer[MAXREM];
          494   FILE *f;
          495   char *destblklst = (char *)malloc( strlen(DESTBLOCK)+1 );
          496   char *destblk;
          497 
          498   from = buf_new();
          499   line = buf_new();
          500   field = buf_new();
          501   content = buf_new();
          502   addr = buf_new();
          503   remailer_addr = buf_new();
          504   copy_addr = buf_new();
          505 
          506   if (destblklst == NULL) {
          507     errlog(ERRORMSG, "Can't malloc %n bytes for destblklst.\n", strlen(DESTBLOCK)+1);
          508     goto end;
          509   };
          510 
          511   buf_rewind(message);
          512   while (buf_getheader(message, field, content) == 0)
          513     if (bufieq(field, "from"))
          514       buf_set(from, content);
          515     else if (bufieq(field, "subject"))
          516       buf_cat(message, content);
          517    /* Append the subject to the message body so destination block requests
          518       in the subject line work too (we process the body a few lines down) */
          519   while (buf_getline(message, line) != -1)
          520     if (bufifind(line, "destination-block")) {
          521       buf_clear(addr);
          522       request = 1;
          523       {
          524         int c = 0;
          525 
          526         while (!strileft(line->data + line->ptr, "block"))
          527           line->ptr++;
          528         while (c != ' ' && c != -1)
          529           c = tolower(buf_getc(line));
          530         while (c == ' ')
          531           c = buf_getc(line);
          532         if (c != -1)
          533           do {
          534             buf_appendc(addr, c);
          535             c = buf_getc(line);
          536           } while (c > ' ');
          537       }
          538       if (addr->length == 0) {
          539         rfc822_addr (from, addr);
          540         buf_chop(addr);
          541       }
          542       /* Check whether somebody wants us to block ourselves */
          543       buf_set(copy_addr, addr);
          544       buf_sets(remailer_addr, REMAILERADDR);
          545       if (doblock(remailer_addr, copy_addr, 1)) {
          546         errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
          547         request = 2;
          548         goto end;
          549       }
          550       /* Check if some evil person tries to block a known type II remailer */
          551       num = mix2_rlist(remailer, NULL);
          552       for (i = 0; i < num; i++) {
          553         buf_sets(remailer_addr, remailer[i].addr);
          554         if (doblock(remailer_addr, copy_addr, 1)) {
          555           errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
          556           request = 2;
          557           goto end;
          558         }
          559       }
          560       /* Check if some evil person tries to block a known type I remailer */
          561       num = t1_rlist(remailer, NULL);
          562       for (i = 0; i < num; i++) {
          563         buf_sets(remailer_addr, remailer[i].addr);
          564         if (doblock(remailer_addr, copy_addr, 1)) {
          565           errlog(LOG, "Ignoring blocking request for %b from %b.\n", addr, from);
          566           request = 2;
          567           goto end;
          568         }
          569       }
          570 
          571       if (buf_ieq(addr, from))
          572         errlog(NOTICE, "Blocking request for %b\n", addr);
          573       else
          574         errlog(NOTICE, "Blocking request for %b from %b\n", addr, from);
          575       if (AUTOBLOCK) {
          576         buf_clear(line);
          577         rfc822_addr(addr, line);
          578         if (line->length == 0) {
          579           errlog(LOG, "Nothing to block after rfc822_addr().\n");
          580         } else
          581           if (bufleft(line, "/")) {
          582             errlog(LOG, "Ignoring blocking request: %b is a regex.\n", addr);
          583           } else {
          584             if (strchr(line->data, '@') && strchr(strchr(line->data, '@'), '.')) {
          585               strcpy( destblklst, DESTBLOCK );
          586               destblk = strtok( destblklst, " " );
          587               f = mix_openfile( destblk, "a" );
          588               if (f != NULL) {
          589                 lock(f);
          590 
          591                 buf_chop(line);
          592                 sendinfofile(BLOCKFILE, NULL, line, NULL);
          593                 if (line->length) {
          594                   fprintf(f, "%s\n", line->data);
          595                 } else
          596                   errlog(NOTICE, "%b already blocked.\n", addr);
          597                 unlock(f);
          598                 fclose(f);
          599               } else
          600                 errlog(ERRORMSG, "Can't write to %s.\n", DESTBLOCK);
          601             } else
          602               errlog(WARNING, "Invalid address not added to %s: %b\n", DESTBLOCK,
          603                      addr);
          604           }
          605       }
          606     }
          607 
          608 end:
          609   free( destblklst );
          610   buf_free(from);
          611   buf_free(line);
          612   buf_free(field);
          613   buf_free(content);
          614   buf_free(addr);
          615   buf_free(remailer_addr);
          616   buf_free(copy_addr);
          617 
          618   return (request);
          619 }
          620 
          621 
          622 int idexp(void)
          623 {
          624   FILE *f;
          625   long now, then;
          626   LOCK *i;
          627   idlog_t idbuf;
          628   long fpi = sizeof(idlog_t), fpo = sizeof(idlog_t);
          629 
          630   if (IDEXP == 0)
          631     return (0);
          632 
          633   f = mix_openfile(IDLOG, "rb+");
          634   if (f == NULL)
          635     return (-1);
          636   i = lockfile(IDLOG);
          637   now = time(NULL);
          638   if (fread(&idbuf, 1, sizeof(idlog_t), f) != sizeof(idlog_t)) { /* replace first line */
          639     fclose(f);
          640     unlockfile(i);
          641     return (-1);
          642   }
          643   then = idbuf.time;
          644   memset(idbuf.id,0,sizeof(idbuf.id));
          645   idbuf.time = now - IDEXP;
          646   fseek(f,0,SEEK_SET);
          647   fwrite(&idbuf,1,sizeof(idlog_t),f);
          648   fseek(f,fpi,SEEK_SET); /* this fseek does nothing, but MSVC CRT happilly reads past EOF (!!!) if we do not fseek here :-/ */
          649   while (fread(&idbuf, 1, sizeof(idlog_t), f) == sizeof(idlog_t)) {
          650     fpi+=sizeof(idlog_t);
          651     then = idbuf.time;
          652     if (now - then < IDEXP &&
          653       now - then > - SECONDSPERDAY * 180 )
          654       /* also expire packets that are dated more than half a year in the future.
          655        * That way we get rid of invalid packets introduced by the switch to a
          656        * binary id.log. */
          657     {
          658       fseek(f,fpo,SEEK_SET);
          659       fwrite(&idbuf,1,sizeof(idlog_t),f);
          660       fpo += sizeof(idlog_t);
          661       fseek(f,fpi,SEEK_SET);
          662     }
          663   }
          664 #ifdef _MSC
          665     chsize(fileno(f),fpo);
          666 #else /* end of _MSC */
          667     ftruncate(fileno(f),fpo);
          668 #endif /* else if not _MSC */
          669   fclose(f);
          670   unlockfile(i);
          671   return (0);
          672 }
          673 
          674 
          675 int pgpmaxexp(void)
          676 {
          677   FILE *f;
          678   BUFFER *b;
          679   long now, then;
          680   LOCK *i;
          681   char temp[LINELEN];
          682 
          683   f = mix_openfile(PGPMAXCOUNT, "rb+");
          684   if (f == NULL)
          685     return (-1);
          686   i = lockfile(PGPMAXCOUNT);
          687   b = buf_new();
          688   now = time(NULL);
          689 
          690   while (fgets(temp, sizeof(temp), f) != NULL)
          691     if (sscanf(temp, "%ld", &then) &&
          692         then >= now - SECONDSPERDAY)
          693       buf_appends(b, temp);
          694 
          695   fseek(f,0,SEEK_SET);
          696 
          697   buf_write(b, f);
          698 
          699 #ifdef _MSC
          700     chsize(fileno(f),b->length);
          701 #else /* end of _MSC */
          702     ftruncate(fileno(f),b->length);
          703 #endif /* else if not _MSC */
          704 
          705   fclose(f);
          706   unlockfile(i);
          707   buf_free(b);
          708   return (0);
          709 }