rem2.c (10743B)
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 Mixmaster remailer messages 9 $Id: rem2.c 934 2006-06-24 13:40:39Z rabbi $ */ 10 11 12 #include "mix3.h" 13 #include <string.h> 14 #include <time.h> 15 #include <ctype.h> 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #ifdef POSIX 19 #include <unistd.h> 20 #else /* end of POSIX */ 21 #include <io.h> 22 #endif /* else if not POSIX */ 23 #ifndef _MSC 24 #include <dirent.h> 25 #endif /* not _MSC */ 26 #include <assert.h> 27 28 int mix_dearmor(BUFFER *in, BUFFER *out) 29 { 30 BUFFER *line, *md; 31 int tempbuf = 0; 32 int err = 0; 33 34 line = buf_new(); 35 md = buf_new(); 36 37 if (in == out) { 38 tempbuf = 1; 39 out = buf_new(); 40 } 41 do { 42 err = buf_getline(in, line); 43 if (err == -1) 44 goto end; 45 } 46 while (!bufeq(line, begin_remailer)); 47 48 do { 49 /* skip lines before message digest */ 50 if (buf_getline(in, md) == -1) 51 break; 52 } while (strlen(md->data) != 24); 53 54 decode(in, out); 55 56 err = buf_getline(in, line); 57 if (err != 0 || !bufeq(line, end_remailer)) 58 err = -1; 59 else { 60 digest_md5(out, line); 61 encode(line, 0); 62 if (!buf_eq(md, line)) 63 err = -1; 64 if (out->length != 20480) 65 err = -1; 66 } 67 68 end: 69 if (err == -1) 70 errlog(NOTICE, "Malformatted message.\n"); 71 72 if (tempbuf) { 73 buf_move(in, out); 74 buf_free(out); 75 } 76 buf_free(line); 77 buf_free(md); 78 return (err); 79 } 80 81 static int isnewid(BUFFER *id, long timestamp) 82 /* return values: 83 * 0: ignore message, no error 84 * 1: ok, process message 85 * -1: bad message, send reply 86 */ 87 { 88 FILE *f; 89 int ret = 1; 90 long now, old = 0; 91 LOCK *i = NULL; 92 idlog_t idbuf; 93 94 if (REMAIL == 0) 95 return (1); /* don't keep statistics for the client */ 96 97 now = time(NULL); 98 99 if ((f = mix_openfile(IDLOG, "rb+")) != NULL) { 100 fread(&idbuf,1,sizeof(idlog_t),f); 101 old = idbuf.time; 102 } else { 103 if (IDEXP == 0) { 104 if (timestamp > 0 && timestamp <= now - 7 * SECONDSPERDAY) { 105 errlog(LOG, "Ignoring old message.\n"); 106 return (0); 107 } 108 } else { 109 if ((f = mix_openfile(IDLOG, "wb")) != NULL) { 110 memset(idbuf.id,0,sizeof(idbuf.id)); 111 idbuf.time = now; 112 fwrite(&idbuf,1,sizeof(idlog_t),f); 113 memcpy(idbuf.id,id->data,sizeof(idbuf.id)); 114 idbuf.time = now; 115 fwrite(&idbuf,1,sizeof(idlog_t),f); 116 fclose(f); 117 errlog(NOTICE, "Creating %s\n", IDLOG); 118 } else { 119 errlog(ERRORMSG, "Can't create %s\n", IDLOG); 120 } 121 return (1); 122 } 123 } 124 125 if (now - old < 5 * SECONDSPERDAY) /* never reject messages less than */ 126 old = now - 5 * SECONDSPERDAY; /* 5 days old (== minimum IDEXP) */ 127 128 if (timestamp > 0 && timestamp <= old) { 129 errlog(LOG, "Ignoring old message.\n"); 130 ret = 0; 131 goto end; 132 } 133 i = lockfile(IDLOG); 134 while (fread(&idbuf, 1, sizeof(idlog_t), f) == sizeof(idlog_t)) { 135 if (!memcmp(idbuf.id, id->data, sizeof(idbuf.id))) { 136 char idstr[33]; 137 id_encode(id->data, idstr); 138 errlog(LOG, "Ignoring redundant message: %s.\n", idstr); 139 ret = 0; 140 goto end; 141 } 142 } 143 if (timestamp > now) { 144 errlog(LOG, "Ignoring message with future timestamp.\n"); 145 ret = -1; 146 goto end; 147 } 148 if (ftell(f)%sizeof(idlog_t)) fseek(f,0-(ftell(f)%sizeof(idlog_t)),SEEK_CUR); /* make sure that we're on sizeof(idlog_t) byte boundary */ 149 memcpy(idbuf.id,id->data,sizeof(idbuf.id)); 150 idbuf.time = now; 151 fwrite(&idbuf,1,sizeof(idlog_t),f); 152 end: 153 if (i) 154 unlockfile(i); 155 fclose(f); 156 return (ret); 157 } 158 159 int mix2_decrypt(BUFFER *m) 160 /* 0: ok 161 * -1: error 162 * -2: old message */ 163 { 164 int err = 0; 165 int i; 166 BUFFER *privkey; 167 BUFFER *keyid; 168 BUFFER *dec, *deskey; 169 BUFFER *packetid, *mid, *digest, *addr, *temp, *iv, *ivvec; 170 int type, packet = 0, numpackets = 0, timestamp = 0; 171 BUFFER *body; 172 BUFFER *header, *out; 173 174 privkey = buf_new(); 175 keyid = buf_new(); 176 dec = buf_new(); 177 deskey = buf_new(); 178 packetid = buf_new(); 179 mid = buf_new(); 180 digest = buf_new(); 181 addr = buf_new(); 182 temp = buf_new(); 183 iv = buf_new(); 184 ivvec = buf_new(); 185 body = buf_new(); 186 header = buf_new(); 187 out = buf_new(); 188 189 buf_get(m, keyid, 16); 190 err = db_getseckey(keyid->data, privkey); 191 if (err == -1) 192 goto end; 193 buf_get(m, deskey, buf_getc(m)); 194 err = pk_decrypt(deskey, privkey); 195 if (err == -1 || deskey->length != 24) { 196 err = -1; 197 errlog(NOTICE, "Cannot decrypt message.\n"); 198 goto end; 199 } 200 buf_get(m, iv, 8); 201 buf_get(m, dec, 328); 202 buf_crypt(dec, deskey, iv, DECRYPT); 203 buf_get(dec, packetid, 16); 204 buf_get(dec, deskey, 24); 205 type = buf_getc(dec); 206 switch (type) { 207 case 0: 208 buf_get(dec, ivvec, 152); 209 buf_get(dec, addr, 80); 210 break; 211 case 1: 212 buf_get(dec, mid, 16); 213 buf_get(dec, iv, 8); 214 break; 215 case 2: 216 packet = buf_getc(dec); 217 numpackets = buf_getc(dec); 218 buf_get(dec, mid, 16); 219 buf_get(dec, iv, 8); 220 break; 221 default: 222 errlog(WARNING, "Unknown message type.\n"); 223 err = -1; 224 goto end; 225 } 226 if (dec->data[dec->ptr] == '0' && dec->data[dec->ptr + 1] == '0' && 227 dec->data[dec->ptr + 2] == '0' && dec->data[dec->ptr + 3] == '0' && 228 dec->data[dec->ptr + 4] == '\0') { 229 dec->ptr += 5; 230 timestamp = buf_geti_lo(dec); 231 } else { 232 errlog(LOG, "Ignoring message without timestamp.\n"); 233 err = -1; 234 goto end; 235 } 236 buf_get(dec, digest, 16); 237 238 dec->length = dec->ptr - 16; /* ignore digest */ 239 dec->ptr = dec->length; 240 241 if (!isdigest_md5(dec, digest)) { 242 errlog(NOTICE, "Message digest does not match.\n"); 243 err = -1; 244 goto end; 245 } 246 switch (isnewid(packetid, timestamp * SECONDSPERDAY)) { 247 case 0: err = -2; /* redundant message */ 248 goto end; 249 case -1: err = -1; /* future timestamp */ 250 goto end; 251 } 252 buf_append(body, m->data + 20 * 512, 10240); 253 254 switch (type) { 255 case 0: 256 buf_chop(addr); 257 buf_cat(out, addr); 258 buf_nl(out); 259 for (i = 0; i < 19; i++) { 260 buf_reset(header); 261 buf_append(header, m->data + (i + 1) * 512, 512); 262 buf_reset(iv); 263 buf_append(iv, ivvec->data + i * 8, 8); 264 buf_crypt(header, deskey, iv, DECRYPT); 265 buf_cat(out, header); 266 } 267 buf_reset(header); 268 buf_pad(header, 512); 269 buf_cat(out, header); 270 buf_reset(iv); 271 buf_append(iv, ivvec->data + 144, 8); 272 buf_crypt(body, deskey, iv, DECRYPT); 273 buf_cat(out, body); 274 mix_pool(out, INTERMEDIATE, -1); 275 break; 276 case 1: 277 buf_crypt(body, deskey, iv, DECRYPT); 278 err = v2body_setlen(body); 279 if (err == -1) 280 goto end; 281 assert(body->ptr == 4); 282 v2body(body); 283 break; 284 case 2: 285 buf_crypt(body, deskey, iv, DECRYPT); 286 v2partial(body, mid, packet, numpackets); 287 break; 288 } 289 end: 290 buf_free(privkey); 291 buf_free(keyid); 292 buf_free(dec); 293 buf_free(deskey); 294 buf_free(packetid); 295 buf_free(mid); 296 buf_free(digest); 297 buf_free(addr); 298 buf_free(temp); 299 buf_free(iv); 300 buf_free(ivvec); 301 buf_free(body); 302 buf_free(header); 303 buf_free(out); 304 305 return (err); 306 } 307 308 int v2body_setlen(BUFFER *body) 309 { 310 long length; 311 312 length = buf_getl_lo(body); 313 if (length < 0 || length > body->length) 314 return (-1); 315 body->length = length + 4; 316 return (0); 317 } 318 319 int v2body(BUFFER *body) 320 { 321 int i, n; 322 BUFFER *to, *newsgroups; 323 BUFFER *temp, *out; 324 BUFFER *line; 325 int type = MSG_MAIL; 326 int subject = 0; 327 328 line = buf_new(); 329 to = buf_new(); 330 newsgroups = buf_new(); 331 temp = buf_new(); 332 out = buf_new(); 333 334 n = buf_getc(body); 335 for (i = 0; i < n; i++) { 336 buf_get(body, line, 80); 337 buf_chop(line); 338 if (bufileft(line, "null:")) 339 goto end; 340 if (bufileft(line, "post:")) { 341 type = MSG_POST; 342 if (line->length > 5) { 343 int j = 5; 344 345 while (j < line->length && isspace(line->data[j])) 346 j++; 347 if (newsgroups->length > 0) 348 buf_appends(newsgroups, ","); 349 buf_append(newsgroups, line->data + j, line->length - j); 350 } 351 } else { 352 if (to->length > 0) 353 buf_appends(to, ","); 354 buf_cat(to, line); 355 } 356 } 357 if (to->length > 0) { 358 buf_appends(out, "To: "); 359 buf_cat(out, to); 360 buf_nl(out); 361 } 362 if (newsgroups->length > 0) { 363 buf_appends(out, "Newsgroups: "); 364 buf_cat(out, newsgroups); 365 buf_nl(out); 366 } 367 n = buf_getc(body); 368 for (i = 0; i < n; i++) { 369 buf_get(body, line, 80); 370 buf_chop(line); 371 if (bufileft(line, "Subject:")) 372 subject = 1; 373 buf_cat(out, line); 374 buf_nl(out); 375 } 376 377 buf_rest(temp, body); 378 buf_uncompress(temp); 379 buf_set(body, temp); 380 buf_reset(temp); 381 382 if (buf_lookahead(body, line) == 0 && isline(line, HASHMARK)) { 383 buf_getline(body, line); 384 while (buf_getline(body, line) == 0) { 385 if (bufileft(line, "subject:")) 386 subject = 1; 387 buf_cat(out, line); 388 buf_nl(out); 389 } 390 } 391 if (type == MSG_POST && !subject) 392 buf_appends(out, "Subject: (no subject)\n"); 393 394 buf_nl(out); 395 buf_rest(out, body); 396 buf_reset(body); 397 mix_pool(out, type, -1); 398 399 end: 400 buf_free(line); 401 buf_free(to); 402 buf_free(newsgroups); 403 buf_free(temp); 404 buf_free(out); 405 return (0); 406 } 407 408 int v2_merge(BUFFER *mid) 409 { 410 char fname[PATHMAX], line[LINELEN]; 411 BUFFER *temp, *msg; 412 FILE *l, *f; 413 int i, numpackets; 414 struct stat sb; 415 long d; 416 int n; 417 int err = -1; 418 419 temp = buf_new(); 420 msg = buf_new(); 421 pool_packetfile(fname, mid, 0); 422 l = fopen(fname, "a+"); 423 if (l != NULL) 424 lock(l); 425 426 pool_packetfile(fname, mid, 1); 427 f = fopen(fname, "rb"); 428 if (f == NULL) 429 goto end; 430 fscanf(f, "%32s %ld %d %d\n", line, &d, &i, &numpackets); 431 fclose(f); 432 433 /* do we have all packets? */ 434 for (i = 1; i <= numpackets; i++) { 435 pool_packetfile(fname, mid, i); 436 if (stat(fname, &sb) != 0) 437 goto end; 438 } 439 errlog(LOG, "Reassembling multipart message.\n"); 440 for (i = 1; i <= numpackets; i++) { 441 pool_packetfile(fname, mid, i); 442 f = fopen(fname, "rb"); 443 if (f == NULL) 444 goto end; 445 fscanf(f, "%32s %ld %d %d\n", line, &d, &n, &n); 446 buf_clear(temp); 447 buf_read(temp, f); 448 v2body_setlen(temp); 449 buf_append(msg, temp->data + 4, temp->length - 4); 450 fclose(f); 451 unlink(fname); 452 } 453 err = v2body(msg); 454 455 end: 456 if (l != NULL) 457 fclose(l); 458 pool_packetfile(fname, mid, 0); 459 unlink(fname); 460 buf_free(temp); 461 buf_free(msg); 462 return (err); 463 } 464 465 int v2partial(BUFFER *m, BUFFER *mid, int packet, int numpackets) 466 { 467 char fname[PATHMAX], idstr[33]; 468 FILE *f; 469 int err = 1; 470 471 pool_packetfile(fname, mid, packet); 472 f = fopen(fname, "wb"); 473 if (f == NULL) { 474 err = -1; 475 goto end; 476 } 477 id_encode(mid->data, idstr); 478 fprintf(f, "%s %ld %d %d\n", idstr, (long) time(NULL), packet, 479 numpackets); 480 buf_write(m, f); 481 buf_reset(m); 482 fclose(f); 483 v2_merge(mid); 484 end: 485 return (err); 486 }