URI: 
       tchain2.c - mixmaster - mixmaster 3.0 patched for libressl
  HTML git clone git://parazyd.org/mixmaster.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       tchain2.c (20338B)
       ---
            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    Encrypt message for Mixmaster chain
            9    $Id: chain2.c 934 2006-06-24 13:40:39Z rabbi $ */
           10 
           11 
           12 #include "mix3.h"
           13 #include <string.h>
           14 #include <stdlib.h>
           15 #include <time.h>
           16 #include <ctype.h>
           17 #include <assert.h>
           18 
           19 #define N(X) (isdigit(X) ? (X)-'0' : 0)
           20 
           21 int prepare_type2list(BUFFER *out)
           22 {
           23   FILE *list;
           24   char line[LINELEN], name[LINELEN], addr[LINELEN], keyid[LINELEN],
           25   version[LINELEN], flags[LINELEN], createdstr[LINELEN], expiresstr[LINELEN];
           26   int assigned;
           27   time_t created, expires;
           28 
           29   list = mix_openfile(PUBRING, "r");
           30   if (list == NULL)
           31     return (-1);
           32   while (fgets(line, sizeof(line), list) != NULL) {
           33     if (strleft(line, begin_key)) {
           34       while (fgets(line, sizeof(line), list) != NULL &&
           35              !strleft(line, end_key)) ;
           36     } else if (strlen(line) > 36 && line[0] != '#') {
           37       assigned = sscanf(line, "%127s %127s %127s %127s %127s %127s %127s",
           38                  name, addr, keyid, version, flags, createdstr, expiresstr);
           39       if (assigned < 4)
           40         continue;
           41       if (assigned >= 6) {
           42         created = parse_yearmonthday(createdstr);
           43         if (created == 0 || created == -1) {
           44           errlog(WARNING, "Cannot parse creation date of key %s.\n", keyid);
           45           continue;
           46         };
           47         if (created > time(NULL)) {
           48           errlog(WARNING, "Key %s created in the future.\n", keyid);
           49           continue;
           50         };
           51       }
           52       if (assigned >= 7) {
           53         expires = parse_yearmonthday(expiresstr);
           54         if (expires == 0 || expires == -1) {
           55           errlog(WARNING, "Cannot parse expiration date of key %s.\n", keyid);
           56           continue;
           57         };
           58         if (expires < time(NULL)) {
           59           errlog(WARNING, "Key %s has expired.\n", keyid);
           60           continue;
           61         };
           62       }
           63       buf_appends(out, line);
           64     }
           65   }
           66   fclose(list);
           67   return (0);
           68 }
           69 
           70 int mix2_rlist(REMAILER remailer[], int badchains[MAXREM][MAXREM])
           71 {
           72   FILE *list, *excl;
           73   int n, i, listed = 0;
           74 
           75   char line[LINELEN], name[LINELEN], addr[LINELEN], keyid[LINELEN],
           76   version[LINELEN], flags[LINELEN], createdstr[LINELEN], expiresstr[LINELEN];
           77   int assigned;
           78   time_t created, expires;
           79   BUFFER *starex;
           80 
           81   starex = buf_new();
           82   excl = mix_openfile(STAREX, "r");
           83   if (excl != NULL) {
           84     buf_read(starex, excl);
           85     fclose(excl);
           86   }
           87 
           88   list = mix_openfile(PUBRING, "r");
           89   if (list == NULL) {
           90     buf_free(starex);
           91     return (-1);
           92   }
           93   for (n = 1; fgets(line, sizeof(line), list) != NULL && n < MAXREM;)
           94     if (strleft(line, begin_key)) {
           95       while (fgets(line, sizeof(line), list) != NULL &&
           96              !strleft(line, end_key)) ;
           97     } else if (strlen(line) > 36 && line[0] != '#') {
           98       flags[0] = '\0';
           99       assigned = sscanf(line, "%127s %127s %127s %127s %127s %127s %127s",
          100                  name, addr, keyid, version, flags, createdstr, expiresstr);
          101       if (assigned < 4)
          102         continue;
          103       if (assigned >= 6) {
          104         created = parse_yearmonthday(createdstr);
          105         if (created == 0 || created == -1) {
          106           errlog(WARNING, "Cannot parse creation date of key %s.\n", keyid);
          107           continue;
          108         };
          109         if (created > time(NULL)) {
          110           errlog(WARNING, "Key %s created in the future.\n", keyid);
          111           continue;
          112         };
          113       }
          114       if (assigned >= 7) {
          115         expires = parse_yearmonthday(expiresstr);
          116         if (expires == 0 || expires == -1) {
          117           errlog(WARNING, "Cannot parse expiration date of key %s.\n", keyid);
          118           continue;
          119         };
          120         if (expires < time(NULL)) {
          121           errlog(WARNING, "Key %s has expired.\n", keyid);
          122           continue;
          123         };
          124       }
          125       strncpy(remailer[n].name, name, sizeof(remailer[n].name));
          126       remailer[n].name[sizeof(remailer[n].name) - 1] = '\0';
          127       strncpy(remailer[n].addr, addr, sizeof(remailer[n].addr));
          128       remailer[n].addr[sizeof(remailer[n].addr) - 1] = '\0';
          129       remailer[n].flags.mix = 1;
          130       remailer[n].flags.cpunk = 0;
          131       remailer[n].flags.nym = 0;
          132       remailer[n].flags.newnym = 0;
          133       id_decode(keyid, remailer[n].keyid);
          134       remailer[n].version = N(version[0]);
          135       remailer[n].flags.compress = strfind(flags, "C");
          136       remailer[n].flags.post = strfind(flags, "N");
          137       remailer[n].flags.middle = strfind(flags, "M");
          138       remailer[n].info[0].reliability = 0;
          139       remailer[n].info[0].latency = 0;
          140       remailer[n].info[0].history[0] = '\0';
          141       remailer[n].flags.star_ex = bufifind(starex, name);
          142       n++;
          143     }
          144   fclose(list);
          145   list = mix_openfile(TYPE2REL, "r");
          146   if (list != NULL) {
          147     while (fgets(line, sizeof(line), list) != NULL &&
          148            !strleft(line, "--------------------------------------------")) {
          149       if (strleft(line, "Last update:")) {
          150         int generated;
          151         int now = time(NULL);
          152         char *tmp = line + strlen("Last update:") + 1;
          153         generated = parsedate(tmp);
          154         if (generated == -1) {
          155           /* For some weird reason, this isn't rfc822 */
          156           if (strleft(tmp, "Mon") ||
          157               strleft(tmp, "Tue") ||
          158               strleft(tmp, "Wed") ||
          159               strleft(tmp, "Thu") ||
          160               strleft(tmp, "Fri") ||
          161               strleft(tmp, "Sat") ||
          162               strleft(tmp, "Sun"))
          163             tmp += 3;
          164           generated = parsedate(tmp);
          165         }
          166         now = time(NULL);
          167         if (generated != -1 && generated < now - SECONDSPERDAY)
          168           errlog(WARNING, "Remailer Reliability Statistics are older than one day (check your clock?).\n");
          169         if (generated != -1 && generated > now)
          170           errlog(WARNING, "Remailer Reliability Statistics are from the future (check your clock?).\n");
          171       }
          172     };
          173     while (fgets(line, sizeof(line), list) != NULL &&
          174            !strleft(line, "</PRE>"))
          175       if (strlen(line) >= 44 && strlen(line) <= 46)
          176         for (i = 1; i < n; i++)
          177           if (strleft(line, remailer[i].name) &&
          178               line[strlen(remailer[i].name)] == ' ') {
          179             strncpy(remailer[i].info[0].history, line + 15, 12);
          180             remailer[i].info[0].history[12] = '\0';
          181             remailer[i].info[0].reliability = 10000 * N(line[37])
          182               + 1000 * N(line[38]) + 100 * N(line[39])
          183               + 10 * N(line[41]) + N(line[42]);
          184             remailer[i].info[0].latency = 36000 * N(line[28])
          185               + 3600 * N(line[29]) + 600 * N(line[31])
          186               + 60 * N(line[32]) + 10 * N(line[34])
          187               + N(line[35]);
          188             listed++;
          189           }
          190     fclose(list);
          191   }
          192 
          193   parse_badchains(badchains, TYPE2REL, "Broken type-II remailer chains", remailer, n);
          194   if (listed < 4)                /* we have no valid reliability info */
          195     for (i = 1; i < n; i++)
          196       remailer[i].info[0].reliability = 10000;
          197   buf_free(starex);
          198   return (n);
          199 }
          200 
          201 static int send_packet(int numcopies, BUFFER *packet, int chain[],
          202                        int chainlen, int packetnum, int numpackets,
          203                        BUFFER *mid, REMAILER remailer[], int badchains[MAXREM][MAXREM],
          204                        int maxrem, char *redirect_to, int ignore_constraints_if_necessary,
          205                        BUFFER *feedback)
          206 /*
          207  * Puts a mix packet in the pool.
          208  *
          209  * numcopies   ... how often to put this packet into the pool
          210  *                 i.e. send it.  required that random remailers are in the chain.
          211  * packet      ... the payload, 10240 bytes in size.
          212  * chain       ... the chain to send this message along
          213  * chainlen    ... length of the chain
          214  * packetnum   ... in multi-packet messages (fragmented) the serial of this packet
          215  * numpackets  ...  the total number of packets
          216  * mid         ... the message ID (required for fragmented packets
          217  * remailer    ... information about remailers, their reliabilities, capabilities, etc.
          218  * badchains   ... broken chain information
          219  * maxrem      ... the number of remailers in remailer[] and badchains[]
          220  * redirect_to ... if this is not-null it needs to be an email address.
          221  *                 in this case packet needs to be not only the body, but a
          222  *                 complete mixmaster packet of 20480 bytes in size (20 headers + body).
          223  *                 the chain given is prepended to the one already encrypted in
          224  *                 the existing message.  If this exceeds the allowed 20 hops in total
          225  *                 the message is corrupted, the last node will realize this.
          226  *                 This is useful if you want to reroute an existing mixmaster message
          227  *                 that has foo as the next hop via a chain so that the packet will
          228  *                 actually flow hop1,hop2,hop3,foo,....
          229  * ignore_constraints_if_necessary .. to be used when randhopping messages.
          230  *                 if a chain can not be constructed otherwhise, maxlat, minlat,
          231  *                 and minrel are ignored.
          232  * feedback    ... a buffer to write feedback to
          233  */
          234 {
          235   BUFFER *pid, *out, *header, *other, *encrypted, *key, *body;
          236   BUFFER *iv, *ivarray, *temp;
          237   BUFFER *pubkey;
          238   char addr[LINELEN];
          239   int thischain[20];
          240   int hop;
          241   int c, i;
          242   int timestamp = 0;
          243   int israndom = 0;
          244   int err = 1;
          245 
          246   body = buf_new();
          247   pid = buf_new();
          248   out = buf_new();
          249   header = buf_new();
          250   other = buf_new();
          251   key = buf_new();
          252   encrypted = buf_new();
          253   iv = buf_new();
          254   ivarray = buf_new();
          255   temp = buf_new();
          256 
          257   if (redirect_to != NULL) {
          258     assert(packet->length == 20480);
          259     buf_append(header, packet->data, 10240);
          260     buf_append(temp, packet->data + 10240, 10240);
          261     buf_clear(packet);
          262     buf_cat(packet, temp);
          263   } else 
          264     assert(packet->length == 10240);
          265 
          266   buf_setrnd(pid, 16);
          267 
          268   for (c = 0; c < numcopies; c++) {
          269     buf_set(body, packet);
          270 
          271     for (hop = 0; hop < chainlen; hop++)
          272       thischain[hop] = chain[hop];
          273 
          274     israndom = chain_rand(remailer, badchains, maxrem, thischain, chainlen, 0, ignore_constraints_if_necessary);
          275     if (israndom == -1) {
          276       err = -1;
          277       clienterr(feedback, "No reliable remailers!");
          278     }
          279     if ((numcopies > 1 || numpackets > 1) && !israndom && (chainlen != 1)) {
          280       clienterr(feedback,
          281                 "Multi-packet message without random remailers!");
          282       err = -1;
          283       goto end;
          284     }
          285     for (hop = 0; hop < chainlen; hop++) {
          286       switch (remailer[thischain[hop]].version) {
          287       case 2:
          288       case 3:                        /* not implemented yet; fall back to version 2 */
          289         /* create header chart to be encrypted with the session key */
          290         if (numcopies > 1 && hop == 0 && redirect_to == NULL)
          291           buf_set(encrypted, pid);        /* same ID only at final hop */
          292         else
          293           buf_setrnd(encrypted, 16);
          294         buf_setrnd(key, 24);        /* key for encrypting the body */
          295         buf_cat(encrypted, key);
          296         buf_setrnd(iv, 8);        /* IV for encrypting the body */
          297 
          298         if (hop > 0 || redirect_to != NULL) {
          299           /* IVs for header chart encryption */
          300           buf_setrnd(ivarray, 18 * 8);
          301           buf_cat(ivarray, iv);        /* 19th IV equals the body IV */
          302 
          303           buf_appendc(encrypted, 0);
          304           buf_cat(encrypted, ivarray);
          305           memset(addr, 0, 80);
          306           if (hop == 0) {
          307             assert(redirect_to != NULL);
          308             strncpy(addr, redirect_to, 80);
          309           } else {
          310             assert(hop > 0);
          311             strcpy(addr, remailer[thischain[hop - 1]].addr);
          312           };
          313           buf_append(encrypted, addr, 80);
          314         } else {
          315           if (numpackets == 1)
          316             buf_appendc(encrypted, 1);
          317           else {
          318             buf_appendc(encrypted, 2);
          319             buf_appendc(encrypted, (byte) packetnum);
          320             buf_appendc(encrypted, (byte) numpackets);
          321           }
          322           buf_cat(encrypted, mid);
          323           buf_cat(encrypted, iv);        /* body encryption IV */
          324         }
          325 
          326         /* timestamp */
          327         buf_appends(encrypted, "0000");
          328         buf_appendc(encrypted, '\0');        /* timestamp magic */
          329         timestamp = time(NULL) / SECONDSPERDAY - rnd_number(4);
          330         buf_appendi_lo(encrypted, timestamp);
          331 
          332         /* message digest for this header */
          333         digest_md5(encrypted, temp);
          334         buf_cat(encrypted, temp);
          335         buf_pad(encrypted, 328);
          336 
          337         /* encrypt message body */
          338         buf_crypt(body, key, iv, ENCRYPT);
          339 
          340         if (hop > 0 || redirect_to != NULL) {
          341           /* encrypt the other header charts */
          342           buf_clear(other);
          343           for (i = 0; i < 19; i++) {
          344             buf_clear(iv);
          345             buf_clear(temp);
          346             buf_append(iv, ivarray->data + 8 * i, 8);
          347             buf_append(temp, header->data + 512 * i, 512);
          348             buf_crypt(temp, key, iv, ENCRYPT);
          349             buf_cat(other, temp);
          350           }
          351         } else
          352           buf_setrnd(other, 19 * 512);        /* fill with random data */
          353 
          354         /* create session key and IV to encrypt the header ... */
          355         buf_setrnd(key, 24);
          356         buf_setrnd(iv, 8);
          357         buf_crypt(encrypted, key, iv, ENCRYPT);
          358         pubkey = buf_new();
          359         err = db_getpubkey(remailer[thischain[hop]].keyid, pubkey);
          360         if (err == -1)
          361           goto end;
          362         err = pk_encrypt(key, pubkey);        /* ... and encrypt the
          363                                            session key */
          364         buf_free(pubkey);
          365         if (err == -1 || key->length != 128) {
          366           clienterr(feedback, "Encryption failed!");
          367           err = -1;
          368           goto end;
          369         }
          370         /* now build the new header */
          371         buf_clear(header);
          372         buf_append(header, remailer[thischain[hop]].keyid, 16);
          373         buf_appendc(header, 128);
          374         buf_cat(header, key);
          375         buf_cat(header, iv);
          376         buf_cat(header, encrypted);
          377         buf_pad(header, 512);
          378         buf_cat(header, other);
          379         break;
          380       default:
          381         err = -1;
          382         goto end;
          383       }
          384     }
          385 
          386     /* build the message */
          387     buf_sets(out, remailer[thischain[chainlen - 1]].addr);
          388     buf_nl(out);
          389     buf_cat(out, header);
          390     buf_cat(out, body);
          391     assert(header->length == 10240 && body->length == 10240);
          392     mix_pool(out, INTERMEDIATE, -1);
          393 
          394     if (feedback) {
          395       for (hop = chainlen - 1; hop >= 0; hop--) {
          396         buf_appends(feedback, remailer[thischain[hop]].name);
          397         if (hop > 0)
          398           buf_appendc(feedback, ',');
          399       }
          400       buf_nl(feedback);
          401     }
          402   }
          403 end:
          404   buf_free(pid);
          405   buf_free(body);
          406   buf_free(out);
          407   buf_free(header);
          408   buf_free(temp);
          409   buf_free(other);
          410   buf_free(key);
          411   buf_free(encrypted);
          412   buf_free(iv);
          413   buf_free(ivarray);
          414   return (err);
          415 }
          416 
          417 int redirect_message(BUFFER *sendmsg, char *chainstr, int numcopies, BUFFER *feedback)
          418 {
          419   BUFFER *field;
          420   BUFFER *content;
          421   BUFFER *line;
          422   char recipient[80] = "";
          423   int num = 0;
          424   int err = 0;
          425   int c;
          426   int hop;
          427 
          428   REMAILER remailer[MAXREM];
          429   int chain[20];
          430   int thischain[20];
          431   int chainlen;
          432   int badchains[MAXREM][MAXREM];
          433   int maxrem;
          434   int tempchain[20];
          435   int tempchainlen;
          436   int israndom;
          437 
          438   field = buf_new();
          439   content = buf_new();
          440   line = buf_new();
          441 
          442   if (numcopies == 0)
          443     numcopies = NUMCOPIES;
          444   if (numcopies > 10)
          445     numcopies = 10;
          446 
          447   /* Find the recipient */
          448   while (buf_getheader(sendmsg, field, content) == 0)
          449     if (bufieq(field, "to")) {
          450       strncpy(recipient, content->data, sizeof(recipient));
          451       num++;
          452     };
          453   if (num != 1) {
          454     clienterr(feedback, "Did not find exactly one To: address!");
          455     err = -1;
          456     goto end;
          457   };
          458 
          459   /* Dearmor the message */
          460   err = mix_dearmor(sendmsg, sendmsg);
          461   if (err == -1)
          462     goto end;
          463   assert (sendmsg->length == 20480);
          464 
          465   /* Check the chain */
          466   maxrem = mix2_rlist(remailer, badchains);
          467   if (maxrem < 1) {
          468     clienterr(feedback, "No remailer list!");
          469     err = -1;
          470     goto end;
          471   }
          472   chainlen = chain_select(chain, chainstr, maxrem, remailer, 0, line);
          473   if (chainlen < 1) {
          474     if (line->length)
          475       clienterr(feedback, line->data);
          476     else
          477       clienterr(feedback, "Invalid remailer chain!");
          478     err = -1;
          479     goto end;
          480   } else if (chainlen >= 20) {
          481     clienterr(feedback, "A chainlength of 20 will certainly destroy the message!");
          482     err = -1;
          483     goto end;
          484   };
          485 
          486 
          487   for (c = 0; c < numcopies; c++) {
          488     /* if our recipient is a remailer we want to make sure we're not using a known broken chain.
          489      * therefore we need to pick the final remailer with care */
          490     for (hop = 0; hop < chainlen; hop++)
          491       thischain[hop] = chain[hop];
          492     if (thischain[0] == 0) {
          493       /* Find out, if recipient is a remailer */
          494       tempchainlen = chain_select(tempchain, recipient, maxrem, remailer, 0, line);
          495       if (tempchainlen < 1 && line->length == 0) {
          496         /* recipient is apparently not a remailer we know about */
          497         ;
          498       } else {
          499         /* Build a new chain, based on the one we already selected but
          500          * with the recipient as the final hop.
          501          * This is so that chain_rand properly selects nodes based on
          502          * broken chains and DISTANCE */
          503         assert(chainlen < 20);
          504         for (hop = 0; hop < chainlen; hop++)
          505           thischain[hop+1] = thischain[hop];
          506         thischain[0] = tempchain[0];
          507 
          508         israndom = chain_rand(remailer, badchains, maxrem, thischain, chainlen + 1, 0, 0);
          509         if (israndom == -1) {
          510           err = -1;
          511           clienterr(feedback, "No reliable remailers!");
          512           goto end;
          513         }
          514 
          515         /* Remove the added recipient hop */
          516         for (hop = 0; hop < chainlen; hop++)
          517           thischain[hop] = thischain[hop + 1];
          518       };
          519     };
          520 
          521     /* queue the packet */
          522     if (send_packet(1, sendmsg, thischain, chainlen,
          523             -1, -1, NULL,
          524             remailer, badchains, maxrem, recipient, 0, feedback) == -1)
          525       err = -1;
          526   };
          527 
          528 end:
          529   buf_free(field);
          530   buf_free(content);
          531   buf_free(line);
          532   return (err);
          533 }
          534 
          535 int mix2_encrypt(int type, BUFFER *message, char *chainstr, int numcopies,
          536                  int ignore_constraints_if_necessary,
          537                  BUFFER *feedback)
          538 {
          539   /* returns 0 on success, -1 on error. feedback contains the selected
          540      remailer chain or an error message
          541 
          542    ignore_constraints_if_necessary .. to be used when randhopping messages.
          543                                    if a chain can not be constructed otherwhise,
          544                                    maxlat, minlat, and minrel are ignored.
          545      */
          546 
          547   REMAILER remailer[MAXREM];
          548   int badchains[MAXREM][MAXREM];
          549   int maxrem;
          550   BUFFER *line, *field, *content, *header, *msgdest, *msgheader, *body,
          551       *temp, *mid;
          552   byte numdest = 0, numhdr = 0;
          553   char hdrline[LINELEN];
          554   BUFFER *packet;
          555   int chain[20];
          556   int chainlen;
          557   int i;
          558   int err = 0;
          559 
          560   mix_init(NULL);
          561   packet = buf_new();
          562   line = buf_new();
          563   field = buf_new();
          564   content = buf_new();
          565   msgheader = buf_new();
          566   msgdest = buf_new();
          567   body = buf_new();
          568   temp = buf_new();
          569   mid = buf_new();
          570   header = buf_new();
          571   if (feedback)
          572     buf_reset(feedback);
          573 
          574   if (numcopies == 0)
          575     numcopies = NUMCOPIES;
          576   if (numcopies > 10)
          577     numcopies = 10;
          578 
          579   maxrem = mix2_rlist(remailer, badchains);
          580   if (maxrem < 1) {
          581     clienterr(feedback, "No remailer list!");
          582     err = -1;
          583     goto end;
          584   }
          585   chainlen = chain_select(chain, chainstr, maxrem, remailer, 0, line);
          586   if (chainlen < 1) {
          587     if (line->length)
          588       clienterr(feedback, line->data);
          589     else
          590       clienterr(feedback, "Invalid remailer chain!");
          591     err = -1;
          592     goto end;
          593   }
          594   if (chain[0] == 0)
          595     chain[0] = chain_randfinal(type, remailer, badchains, maxrem, 0, chain, chainlen, ignore_constraints_if_necessary);
          596 
          597   if (chain[0] == -1) {
          598     clienterr(feedback, "No reliable remailers!");
          599     err = -1;
          600     goto end;
          601   }
          602   switch (remailer[chain[0]].version) {
          603   case 2:
          604     if (type == MSG_NULL) {
          605       memset(hdrline, 0, 80);
          606       strcpy(hdrline, "null:");
          607       buf_append(msgdest, hdrline, 80);
          608       numdest++;
          609     } else
          610       while (buf_getheader(message, field, content) == 0) {
          611         if (bufieq(field, "to")) {
          612           memset(hdrline, 0, 80);
          613           strncpy(hdrline, content->data, 80);
          614           buf_append(msgdest, hdrline, 80);
          615           numdest++;
          616         } else if (type == MSG_POST && bufieq(field, "newsgroups")) {
          617           memset(hdrline, 0, 80);
          618           strcpy(hdrline, "post: ");
          619           strcatn(hdrline, content->data, 80);
          620           buf_append(msgdest, hdrline, 80);
          621           numdest++;
          622         } else {
          623           buf_clear(header);
          624           buf_appendheader(header, field, content);
          625           hdr_encode(header, 80);
          626           while (buf_getline(header, line) == 0) {
          627             /* paste in encoded header entry */
          628             memset(hdrline, 0, 80);
          629             strncpy(hdrline, line->data, 80);
          630             buf_append(msgheader, hdrline, 80);
          631             numhdr++;
          632           }
          633         }
          634       }
          635     buf_appendc(body, numdest);
          636     buf_cat(body, msgdest);
          637     buf_appendc(body, numhdr);
          638     buf_cat(body, msgheader);
          639 
          640     if (type != MSG_NULL) {
          641       buf_rest(temp, message);
          642       if (temp->length > 10236 && remailer[chain[0]].flags.compress)
          643         buf_compress(temp);
          644       buf_cat(body, temp);
          645       buf_reset(temp);
          646     }
          647     buf_setrnd(mid, 16);        /* message ID */
          648     for (i = 0; i <= body->length / 10236; i++) {
          649       long length;
          650 
          651       length = body->length - i * 10236;
          652       if (length > 10236)
          653         length = 10236;
          654       buf_clear(packet);
          655       buf_appendl_lo(packet, length);
          656       buf_append(packet, body->data + i * 10236, length);
          657       buf_pad(packet, 10240);
          658       if (send_packet(numcopies, packet, chain, chainlen,
          659                       i + 1, body->length / 10236 + 1,
          660                       mid, remailer, badchains, maxrem, NULL, ignore_constraints_if_necessary, feedback) == -1)
          661         err = -1;
          662     }
          663     break;
          664   case 3:
          665     NOT_IMPLEMENTED;
          666     break;
          667   default:
          668     fprintf(stderr, "%d\n", chain[0]);
          669     clienterr(feedback, "Unknown remailer version!");
          670     err = -1;
          671   }
          672 
          673 end:
          674   buf_free(packet);
          675   buf_free(line);
          676   buf_free(field);
          677   buf_free(content);
          678   buf_free(header);
          679   buf_free(msgheader);
          680   buf_free(msgdest);
          681   buf_free(body);
          682   buf_free(temp);
          683   buf_free(mid);
          684   return (err);
          685 }