/[pkg-mixmaster]/trunk/Mix/Src/chain2.c
ViewVC logotype

Contents of /trunk/Mix/Src/chain2.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.5