INN commit: branches/2.5/innd (nc.c)
INN Commit
rra at isc.org
Sun Nov 15 09:28:02 UTC 2009
Date: Sunday, November 15, 2009 @ 01:28:02
Author: iulius
Revision: 8792
* Fix a long-standing bug in TAKETHIS: when authentication
was required, a 480 code was answered before having received
the whole multi-data block, which broke the NNTP protocol.
* Implement RFC 3977 and 4644 for streaming. TAKETHIS is
now totally RFC-compliant and checks the syntax.
(However, 501 is still not sent for interoperability reasons).
Modified:
branches/2.5/innd/nc.c
------+
nc.c | 169 +++++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 117 insertions(+), 52 deletions(-)
Modified: nc.c
===================================================================
--- nc.c 2009-11-15 09:27:50 UTC (rev 8791)
+++ nc.c 2009-11-15 09:28:02 UTC (rev 8792)
@@ -230,11 +230,19 @@
cp->State = CSgetcmd;
snprintf(buff, sizeof(buff), "%d %s", NNTP_FAIL_IHAVE_DEFER, ModeReason);
}
- response = buff;
- NCwritereply(cp, response);
+ NCwritereply(cp, buff);
return;
}
+ /* Return an error without trying to post the article if the TAKETHIS
+ * command was not correct in the first place (code which does not start
+ * with a '2'). */
+ if ((cp->Sendid.size > 3) && (cp->Sendid.data[0] != NNTP_CLASS_OK)) {
+ cp->State = CSgetcmd;
+ NCwritereply(cp, cp->Sendid.data);
+ return;
+ }
+
/* Note that some use break, some use return here. */
if (ARTpost(cp)) {
cp->Received++;
@@ -250,23 +258,27 @@
response = buff;
}
} else {
- /* The answer to TAKETHIS is a response code followed by a
- * message-ID. The response code is already NNTP_FAIL_TAKETHIS_REJECT. */
- if (cp->Sendid.size)
+ /* The answer to TAKETHIS is a response code followed by a message-ID. */
+ if (cp->Sendid.size > 3) {
+ snprintf(buff, sizeof(buff), "%d", NNTP_FAIL_TAKETHIS_REJECT);
+ cp->Sendid.data[0] = buff[0];
+ cp->Sendid.data[1] = buff[1];
+ cp->Sendid.data[2] = buff[2];
response = cp->Sendid.data;
- else
+ } else {
response = cp->Error;
+ }
}
cp->Reported++;
if (cp->Reported >= innconf->incominglogfrequency) {
snprintf(buff, sizeof(buff),
- "accepted size %.0f duplicate size %.0f rejected size %.0f",
- cp->Size, cp->DuplicateSize, cp->RejectSize);
+ "accepted size %.0f duplicate size %.0f rejected size %.0f",
+ cp->Size, cp->DuplicateSize, cp->RejectSize);
syslog(L_NOTICE,
- "%s checkpoint seconds %ld accepted %ld refused %ld rejected %ld duplicate %ld %s",
- CHANname(cp), (long)(Now.tv_sec - cp->Started),
- cp->Received, cp->Refused, cp->Rejected,
- cp->Duplicate, buff);
+ "%s checkpoint seconds %ld accepted %ld refused %ld rejected %ld duplicate %ld %s",
+ CHANname(cp), (long)(Now.tv_sec - cp->Started),
+ cp->Received, cp->Refused, cp->Rejected,
+ cp->Duplicate, buff);
cp->Reported = 0;
}
@@ -1157,33 +1169,38 @@
for (dp = NCcommands; dp < ARRAY_END(NCcommands); dp++) {
if ((dp->Function != NC_unimp) &&
(strcasecmp(cp->av[0], dp->Name) == 0)) {
- if (!StreamingOff || cp->Streaming ||
- (dp->Function != NCcheck && dp->Function != NCtakethis)) {
- validcommandtoolong = true;
- }
- /* Return 435/438 instead of 501 to IHAVE/CHECK commands
- * for compatibility reasons. */
- if (strcasecmp(cp->av[0], "IHAVE") == 0) {
- syntaxerrorcode = NNTP_FAIL_IHAVE_REFUSE;
- } else if (strcasecmp(cp->av[0], "CHECK") == 0
- && (!StreamingOff || cp->Streaming)) {
- syntaxerrorcode = NNTP_FAIL_CHECK_REFUSE;
- }
+ if (!StreamingOff || cp->Streaming ||
+ (dp->Function != NCcheck && dp->Function != NCtakethis)) {
+ validcommandtoolong = true;
+ }
+ /* Return 435/438 instead of 501 to IHAVE/CHECK commands
+ * for compatibility reasons. */
+ if (strcasecmp(cp->av[0], "IHAVE") == 0) {
+ syntaxerrorcode = NNTP_FAIL_IHAVE_REFUSE;
+ } else if (strcasecmp(cp->av[0], "CHECK") == 0
+ && (!StreamingOff || cp->Streaming)) {
+ syntaxerrorcode = NNTP_FAIL_CHECK_REFUSE;
+ }
}
}
- if (syntaxerrorcode == NNTP_FAIL_CHECK_REFUSE) {
+ /* If TAKETHIS, we have to read the entire multi-line response
+ * block before answering. */
+ if (strcasecmp(cp->av[0], "TAKETHIS") != 0
+ || (StreamingOff && !cp->Streaming)) {
+ if (syntaxerrorcode == NNTP_FAIL_CHECK_REFUSE) {
snprintf(buff, sizeof(buff), "%d %s", syntaxerrorcode,
cp->ac > 1 ? cp->av[1] : "");
- } else {
+ } else {
snprintf(buff, sizeof(buff), "%d Line too long",
validcommandtoolong ? syntaxerrorcode : NNTP_ERR_COMMAND);
+ }
+ NCwritereply(cp, buff);
+ cp->Start = cp->Next;
+
+ syslog(L_NOTICE, "%s bad_command %s", CHANname(cp),
+ MaxLength(q, q));
+ break;
}
- NCwritereply(cp, buff);
- cp->Start = cp->Next;
-
- syslog(L_NOTICE, "%s bad_command %s", CHANname(cp),
- MaxLength(q, q));
- break;
}
/* Loop through the command table. */
@@ -1255,12 +1272,17 @@
snprintf(buff, sizeof(buff), "%d Argument too long",
syntaxerrorcode);
}
+ break;
+ }
+ if (validcommandtoolong) {
+ /* If TAKETHIS, we have to read the entire multi-line response
+ * block before answering. */
+ if (strcasecmp(cp->av[0], "TAKETHIS") != 0
+ || (StreamingOff && !cp->Streaming)) {
NCwritereply(cp, buff);
+ cp->Start = cp->Next;
break;
}
- if (validcommandtoolong) {
- cp->Start = cp->Next;
- break;
}
}
@@ -1274,9 +1296,14 @@
snprintf(buff, sizeof(buff), "%d Syntax is: %s %s",
syntaxerrorcode, dp->Name, dp->Help ? dp->Help : "(no argument allowed)");
}
- NCwritereply(cp, buff);
- cp->Start = cp->Next;
- break;
+ /* If TAKETHIS, we have to read the entire multi-line response
+ * block before answering. */
+ if (strcasecmp(cp->av[0], "TAKETHIS") != 0
+ || (StreamingOff && !cp->Streaming)) {
+ NCwritereply(cp, buff);
+ cp->Start = cp->Next;
+ break;
+ }
}
/* Check permissions and dispatch. */
@@ -1289,9 +1316,14 @@
snprintf(buff, sizeof(buff),
"%d Access denied", NNTP_ERR_ACCESS);
}
- NCwritereply(cp, buff);
- cp->Start = cp->Next;
- break;
+ /* If TAKETHIS, we have to read the entire multi-line response
+ * block before answering. */
+ if (strcasecmp(cp->av[0], "TAKETHIS") != 0
+ || (StreamingOff && !cp->Streaming)) {
+ NCwritereply(cp, buff);
+ cp->Start = cp->Next;
+ break;
+ }
}
(*dp->Function)(cp);
@@ -1339,10 +1371,21 @@
NCclearwip(cp);
/* The answer to TAKETHIS is a response code followed by a
* message-ID. */
- if (cp->Sendid.size > 3)
+ if (cp->Sendid.size > 3) {
+ /* Return the right response code if the TAKETHIS command
+ * was not correct in the first place (code which does not
+ * start with a '2'). Otherwise, change it to reject the
+ * article. */
+ if (cp->Sendid.data[0] == NNTP_CLASS_OK) {
+ snprintf(buff, sizeof(buff), "%d", NNTP_FAIL_TAKETHIS_REJECT);
+ cp->Sendid.data[0] = buff[0];
+ cp->Sendid.data[1] = buff[1];
+ cp->Sendid.data[2] = buff[2];
+ }
NCwritereply(cp, cp->Sendid.data);
- else
+ } else {
NCwritereply(cp, cp->Error);
+ }
readmore = false;
movedata = false;
break;
@@ -1805,17 +1848,39 @@
static void
NCtakethis(CHANNEL *cp)
{
- size_t msglen;
- WIP *wp;
+ char *mid;
+ static char empty[] = "";
+ int returncode; /* Will *not* be changed in NCpostit()
+ if it does *not* start with '2'. */
+ size_t msglen;
+ WIP *wp;
cp->Takethis++;
cp->Start = cp->Next;
- if (!IsValidMessageID(cp->av[1], false)) {
- syslog(L_NOTICE, "%s bad_messageid %s", CHANname(cp),
- MaxLength(cp->av[1], cp->av[1]));
+ /* Check the syntax and authentication here because
+ * it is not done before (TAKETHIS has to eat
+ * the whole multi-line block before responding). */
+ if (cp->ac == 1) {
+ mid = empty;
+ returncode = NNTP_FAIL_TAKETHIS_REJECT;
+ } else {
+ mid = cp->av[1];
+ returncode = NNTP_OK_TAKETHIS; /* Default code. */
}
- msglen = strlen(cp->av[1]) + 5; /* 3 digits + space + id + null. */
+ if (!IsValidMessageID(mid, false)) {
+ syslog(L_NOTICE, "%s bad_messageid %s", CHANname(cp),
+ MaxLength(mid, mid));
+ returncode = NNTP_FAIL_TAKETHIS_REJECT;
+ }
+
+ /* Check authentication after everything else. */
+ if (!cp->IsAuthenticated) {
+ returncode = cp->CanAuthenticate ?
+ NNTP_FAIL_AUTH_NEEDED : NNTP_ERR_ACCESS;
+ }
+
+ msglen = strlen(mid) + 5; /* 3 digits + space + id + null. */
if (cp->Sendid.size < msglen) {
if (cp->Sendid.size > 0)
free(cp->Sendid.data);
@@ -1827,14 +1892,14 @@
}
/* Save ID for later NACK or ACK. */
snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_FAIL_TAKETHIS_REJECT, cp->av[1]);
+ returncode, mid);
cp->ArtBeg = Now.tv_sec;
cp->State = CSgetheader;
ARTprepare(cp);
/* Set WIP for benefit of later code in NCreader. */
- if ((wp = WIPbyid(cp->av[1])) == (WIP *)NULL)
- wp = WIPnew(cp->av[1], cp);
+ if ((wp = WIPbyid(mid)) == (WIP *)NULL)
+ wp = WIPnew(mid, cp);
cp->CurrentMessageIDHash = wp->MessageID;
}
More information about the inn-committers
mailing list