@@ -1238,11 +1238,17 @@ void
12381238ARTcancel (const ARTDATA * data , const char * MessageID , const bool Trusted )
12391239{
12401240 char buff [SMBUF + 16 ];
1241+ const char * start , * end ;
1242+ ARTHANDLE * art ;
12411243 TOKEN token ;
1244+ #if defined(HAVE_CANLOCK )
1245+ char * canlockhdr ;
1246+ const HDRCONTENT * hc = data -> HdrContent ;
1247+ #endif
12421248 bool r ;
12431249
12441250 TMRstart (TMR_ARTCNCL );
1245- if (! DoCancels && !Trusted ) {
1251+ if (strcasecmp ( innconf -> docancels , "none" ) == 0 && !Trusted ) {
12461252 TMRstop (TMR_ARTCNCL );
12471253 return ;
12481254 }
@@ -1254,10 +1260,76 @@ ARTcancel(const ARTDATA *data, const char *MessageID, const bool Trusted)
12541260 return ;
12551261 }
12561262
1263+ /* No additional checks if cancels should all be executed. */
1264+ if (strcasecmp (innconf -> docancels , "all" ) != 0 && !Trusted ) {
1265+ /* Retrieve the Cancel-Lock header field of the article to be
1266+ * cancelled. If the original article is not found or has no
1267+ * Cancel-Lock header field, we cannot authenticate the cancel.
1268+ *
1269+ * It also means that we do not honour cancel requests for articles not
1270+ * yet received, even if they do not have a Cancel-Lock header field
1271+ * (but we don't know yet). */
1272+ if (!HISlookup (History , MessageID , NULL , NULL , NULL , & token )) {
1273+ TMRstop (TMR_ARTCNCL );
1274+ return ;
1275+ }
1276+ if ((art = SMretrieve (token , RETR_HEAD )) == NULL ) {
1277+ TMRstop (TMR_ARTCNCL );
1278+ return ;
1279+ }
1280+ start = wire_findheader (art -> data , art -> len , "Cancel-Lock" , true);
1281+
1282+ if (start == NULL
1283+ && strcasecmp (innconf -> docancels , "require-auth" ) == 0 ) {
1284+ SMfreearticle (art );
1285+ TMRstop (TMR_ARTCNCL );
1286+ return ;
1287+ } else if (start != NULL ) {
1288+ /* canlockhdr will store a copy of the Cancel-Lock header field
1289+ * body of the original article to be cancelled.
1290+ * end points to the final "\n" of the header field body. */
1291+ end = wire_endheader (start , art -> data + art -> len - 1 );
1292+
1293+ if (end == NULL
1294+ && strcasecmp (innconf -> docancels , "require-auth" ) == 0 ) {
1295+ SMfreearticle (art );
1296+ TMRstop (TMR_ARTCNCL );
1297+ return ;
1298+ } else if (end != NULL ) {
1299+ r = false;
1300+ #if defined(HAVE_CANLOCK )
1301+ if (HDR (HDR__CANCEL_KEY ) != NULL ) {
1302+ canlockhdr = xstrndup (start , end - start );
1303+
1304+ /* Is the Cancel-Key header field legitimate? */
1305+ r = verify_cancel_key (HDR (HDR__CANCEL_KEY ), canlockhdr );
1306+
1307+ free (canlockhdr );
1308+ }
1309+ #endif
1310+ SMfreearticle (art );
1311+
1312+ if (r == false) {
1313+ TMRstop (TMR_ARTCNCL );
1314+ return ;
1315+ }
1316+ } else {
1317+ /* docancels is "auth", and there is no Cancel-Lock. */
1318+ SMfreearticle (art );
1319+ }
1320+ } else {
1321+ /* docancels is "auth", and there is no Cancel-Lock. */
1322+ SMfreearticle (art );
1323+ }
1324+ }
1325+
12571326 if (!HIScheck (History , MessageID )) {
12581327 /* Article hasn't arrived here, so write a fake entry using
12591328 * most of the information from the cancel message. */
1260- if (innconf -> verifycancels && !Trusted ) {
1329+ if (innconf -> verifycancels
1330+ && (strcasecmp (innconf -> docancels , "require-auth" ) == 0
1331+ || strcasecmp (innconf -> docancels , "auth" ) == 0 )
1332+ && !Trusted ) {
12611333 TMRstop (TMR_ARTCNCL );
12621334 return ;
12631335 }
@@ -2673,7 +2745,7 @@ ARTpost(CHANNEL *cp)
26732745 if (IsControl ) {
26742746 ARTcontrol (data , HDR (HDR__CONTROL ), cp );
26752747 }
2676- if (DoCancels && HDR_FOUND (HDR__SUPERSEDES )) {
2748+ if (HDR_FOUND (HDR__SUPERSEDES )) {
26772749 if (IsValidMessageID (HDR (HDR__SUPERSEDES ), true, laxmid ))
26782750 ARTcancel (data , HDR (HDR__SUPERSEDES ), false);
26792751 }
0 commit comments