410
* Reads the next mail address from the given string and returns it in an
411
* allocated buffer. If no mail address is found, NULL will be returned.
412
* If a buffer is returned, the string in it will only contain the following
413
* characters: letters a-z and A-Z, digits 0-9, and any of ".@_-+/".
414
* Note that this is only a subset of what the RFCs 2821 and 2822 allow!
416
char *pop3_get_addr(const char *s)
418
enum states { STATE_DEFAULT, STATE_DQUOTE,
419
STATE_BRACKETS_START, STATE_IN_BRACKETS,
420
STATE_PARENTH_START, STATE_IN_PARENTH,
421
STATE_IN_ADDRESS, STATE_BACKQUOTE,
423
int state = STATE_DEFAULT;
424
int oldstate = STATE_DEFAULT;
425
int backquote_savestate = STATE_DEFAULT;
426
int parentheses_depth = 0;
427
int parentheses_savestate = STATE_DEFAULT;
433
/* The buffer that is filled with the mail address grows by
434
* 'bufsize_step' if the remaining space becomes too small. This value must
435
* be at least 2. Wasted characters are at most (bufsize_step - 1). A value
436
* of 10 means low wasted space and a low number of realloc()s per
438
const size_t bufsize_step = 10;
457
backquote_savestate = state;
458
state = STATE_BACKQUOTE;
462
parentheses_savestate = state;
463
state = STATE_PARENTH_START;
469
state = STATE_DQUOTE;
475
state = STATE_BRACKETS_START;
477
else if (*p == ' ' || *p == '\t')
484
else if (*p == ';' || *p == ',')
496
state = STATE_IN_ADDRESS;
503
backquote_savestate = state;
504
state = STATE_BACKQUOTE;
507
state = STATE_DEFAULT;
510
case STATE_BRACKETS_START:
513
parentheses_savestate = state;
514
state = STATE_PARENTH_START;
517
state = STATE_DEFAULT;
519
state = STATE_IN_BRACKETS;
522
case STATE_IN_BRACKETS:
525
backquote_savestate = state;
526
state = STATE_BACKQUOTE;
530
parentheses_savestate = state;
531
state = STATE_PARENTH_START;
540
case STATE_PARENTH_START:
542
state = parentheses_savestate;
546
state = STATE_IN_PARENTH;
550
case STATE_IN_PARENTH:
553
backquote_savestate = state;
554
state = STATE_BACKQUOTE;
557
state = STATE_PARENTH_START;
561
if (parentheses_depth == 0)
562
state = parentheses_savestate;
566
case STATE_IN_ADDRESS:
569
backquote_savestate = state;
570
state = STATE_BACKQUOTE;
575
state = STATE_DQUOTE;
579
parentheses_savestate = state;
580
state = STATE_PARENTH_START;
585
state = STATE_BRACKETS_START;
587
else if (*p == ' ' || *p == '\t')
588
state = STATE_DEFAULT;
592
state = STATE_DEFAULT;
594
else if (*p == ',' || *p == ';')
601
case STATE_BACKQUOTE:
602
state = backquote_savestate;
609
/* this was just junk */
618
addr[addr_len] = '\0';
620
if (state == STATE_END)
624
if ((state == STATE_IN_ADDRESS || state == STATE_IN_BRACKETS)
625
&& oldstate != STATE_PARENTH_START
626
&& oldstate != STATE_IN_PARENTH)
628
/* Add this character to the current recipient */
630
if (bufsize < addr_len + 1)
632
bufsize += bufsize_step;
633
addr = xrealloc(addr, bufsize * sizeof(char));
635
/* sanitize characters */
636
if (c_isalpha((unsigned char)*p) || c_isdigit((unsigned char)*p)
637
|| *p == '.' || *p == '@' || *p == '_' || *p == '-'
638
|| *p == '+' || *p == '/')
640
addr[addr_len - 1] = *p;
642
else if (c_isspace((unsigned char)*p))
644
addr[addr_len - 1] = '-';
648
addr[addr_len - 1] = '_';
405
659
* pop3_get_greeting()
429
683
/* 'greeting' is large enough */
430
684
strcpy(greeting, session->buffer + 4);
432
/* search APOP timestamp */
433
if ((p = strchr(session->buffer, '<')) != NULL)
686
/* Search APOP timestamp. Make sure that it is a valid RFC822 message id as
687
* required by RFC 1939 and that it is reasonably long. This should make
688
* man-in-the-middle attacks as described in CVE-2007-1558 a little bit
689
* harder. Nevertheless, APOP is considered broken, and is never used
690
* automatically unless TLS is active. */
692
if ((p = strchr(session->buffer, '<')) != NULL /* start of timestamp */
693
&& (q = strchr(p + 1, '>')) != NULL /* end of timestamp */
694
&& (q - p + 1) >= 12 /* minimum length */
695
&& (a = pop3_get_addr(p)) /* valid address */
696
&& strlen(a) + 2 == (size_t)(q - p + 1) /* no specials */
697
&& strncmp(p + 1, a, q - p - 1) == 0) /* no invalid chars */
435
if ((q = strchr(p, '>')) != NULL)
437
session->cap.flags |= POP3_CAP_AUTH_APOP;
438
session->cap.apop_timestamp = xmalloc((q - p + 2) * sizeof(char));
439
strncpy(session->cap.apop_timestamp, p, q - p + 1);
440
session->cap.apop_timestamp[q - p + 1] = '\0';
699
session->cap.flags |= POP3_CAP_AUTH_APOP;
700
session->cap.apop_timestamp = xmalloc((q - p + 2) * sizeof(char));
701
strncpy(session->cap.apop_timestamp, p, q - p + 1);
702
session->cap.apop_timestamp[q - p + 1] = '\0';
806
1069
const char *p = uid;
808
1071
/* According to RFC 1939, a valid UID must consist of one to 70 characters
809
* in the range 0x21 to 0x7e. We allow longer UIDs, spaces inside UIDs (but
810
* no space at the beginning of an UID), and non-ASCII characters in UIDs
811
* as long as they are not control characters.
1072
* in the range 0x21 to 0x7e. We allow longer UIDs, spaces inside UIDs, and
1073
* non-ASCII characters in UIDs as long as they are not control characters.
812
1074
* I know of one case where the POP3 server uses non-ASCII characters in
813
1075
* UIDs. I don't know if any server needs the other extensions, though. */
818
1076
while (*p != '\0')
820
1078
if (c_iscntrl((unsigned char)*p))
890
1148
if (p == session->buffer || *p != ' '
891
1149
|| (n == LONG_MAX && errno == ERANGE)
892
1150
|| n < 1 || n > session->total_number
893
|| session->msg_uid[n - 1]
894
|| !pop3_uidl_check_uid(p + 1))
1151
|| session->msg_uid[n - 1])
1155
/* Allow more than one space between the number and the UID, even
1156
* though RFC 1939 says it must be exactly one. Needed for the
1157
* "Maillennium V05.00c++" POP3 server used by Comcast.net as of
1163
if (!pop3_uidl_check_uid(p))
896
1165
goto invalid_reply;
1232
* Reads the next mail address from the given string and returns it in an
1233
* allocated buffer. If no mail address is found, NULL will be returned.
1234
* If a buffer is returned, the string in it will only contain the following
1235
* characters: letters a-z and A-Z, digits 0-9, and any of ".@_-+/".
1236
* Note that this is only a subset of what the RFCs 2821 and 2822 allow!
1238
char *pop3_get_addr(const char *s)
1240
enum states { STATE_DEFAULT, STATE_DQUOTE,
1241
STATE_BRACKETS_START, STATE_IN_BRACKETS,
1242
STATE_PARENTH_START, STATE_IN_PARENTH,
1243
STATE_IN_ADDRESS, STATE_BACKQUOTE,
1245
int state = STATE_DEFAULT;
1246
int oldstate = STATE_DEFAULT;
1247
int backquote_savestate = STATE_DEFAULT;
1248
int parentheses_depth = 0;
1249
int parentheses_savestate = STATE_DEFAULT;
1251
size_t addr_len = 0;
1252
int forget_addr = 0;
1253
int finish_addr = 0;
1255
/* The buffer that is filled with the mail address grows by
1256
* 'bufsize_step' if the remaining space becomes too small. This value must
1257
* be at least 2. Wasted characters are at most (bufsize_step - 1). A value
1258
* of 10 means low wasted space and a low number of realloc()s per
1260
const size_t bufsize_step = 10;
1279
backquote_savestate = state;
1280
state = STATE_BACKQUOTE;
1284
parentheses_savestate = state;
1285
state = STATE_PARENTH_START;
1291
state = STATE_DQUOTE;
1297
state = STATE_BRACKETS_START;
1299
else if (*p == ' ' || *p == '\t')
1306
else if (*p == ';' || *p == ',')
1318
state = STATE_IN_ADDRESS;
1325
backquote_savestate = state;
1326
state = STATE_BACKQUOTE;
1329
state = STATE_DEFAULT;
1332
case STATE_BRACKETS_START:
1335
parentheses_savestate = state;
1336
state = STATE_PARENTH_START;
1339
state = STATE_DEFAULT;
1341
state = STATE_IN_BRACKETS;
1344
case STATE_IN_BRACKETS:
1347
backquote_savestate = state;
1348
state = STATE_BACKQUOTE;
1352
parentheses_savestate = state;
1353
state = STATE_PARENTH_START;
1362
case STATE_PARENTH_START:
1364
state = parentheses_savestate;
1367
parentheses_depth++;
1368
state = STATE_IN_PARENTH;
1372
case STATE_IN_PARENTH:
1375
backquote_savestate = state;
1376
state = STATE_BACKQUOTE;
1379
state = STATE_PARENTH_START;
1382
parentheses_depth--;
1383
if (parentheses_depth == 0)
1384
state = parentheses_savestate;
1388
case STATE_IN_ADDRESS:
1391
backquote_savestate = state;
1392
state = STATE_BACKQUOTE;
1397
state = STATE_DQUOTE;
1401
parentheses_savestate = state;
1402
state = STATE_PARENTH_START;
1407
state = STATE_BRACKETS_START;
1409
else if (*p == ' ' || *p == '\t')
1410
state = STATE_DEFAULT;
1414
state = STATE_DEFAULT;
1416
else if (*p == ',' || *p == ';')
1423
case STATE_BACKQUOTE:
1424
state = backquote_savestate;
1431
/* this was just junk */
1440
addr[addr_len] = '\0';
1442
if (state == STATE_END)
1446
if ((state == STATE_IN_ADDRESS || state == STATE_IN_BRACKETS)
1447
&& oldstate != STATE_PARENTH_START
1448
&& oldstate != STATE_IN_PARENTH)
1450
/* Add this character to the current recipient */
1452
if (bufsize < addr_len + 1)
1454
bufsize += bufsize_step;
1455
addr = xrealloc(addr, bufsize * sizeof(char));
1457
/* sanitize characters */
1458
if (c_isalpha((unsigned char)*p) || c_isdigit((unsigned char)*p)
1459
|| *p == '.' || *p == '@' || *p == '_' || *p == '-'
1460
|| *p == '+' || *p == '/')
1462
addr[addr_len - 1] = *p;
1464
else if (c_isspace((unsigned char)*p))
1466
addr[addr_len - 1] = '-';
1470
addr[addr_len - 1] = '_';
1481
1499
* pop3_retr_get_from_addr()