Exemple #1
0
void
DeleteConnection(Connection *conn)
{
    MemPool *mpool = conn->co_MemPool;

    if (conn->co_Desc->d_Type == THREAD_SPOOL) {
	conn->co_LastServerLog = 1;
	LogServerInfo(conn, TFd);
    } else if (conn->co_Desc->d_Type == THREAD_NNTP) {
	char statbuf[1024];
	char vsbuf[11];
	char hsbuf[31];

	snprintf(vsbuf, sizeof(vsbuf), "%s", conn->co_Auth.dr_VServerDef->vs_Name);

	snprintf(hsbuf, sizeof(hsbuf), "%s%s%s%s%s",
		*conn->co_Auth.dr_AuthUser ? conn->co_Auth.dr_AuthUser : "",
		*conn->co_Auth.dr_AuthUser ? "/" : "",
		*conn->co_Auth.dr_IdentUser ? conn->co_Auth.dr_IdentUser : "",
		*conn->co_Auth.dr_IdentUser ? "@" : "",
		conn->co_Auth.dr_Host);
	RTStatusBase(conn->co_Desc->d_Slot, "CLSD %-10s %-30s", vsbuf, hsbuf);

	GroupStats(conn);

	snprintf(statbuf, sizeof(statbuf), "exit articles %lu groups %lu posts %lu bytes %.0f", conn->co_ClientTotalArticleCount, conn->co_ClientGroupCount, conn->co_ClientPostCount, conn->co_ClientTotalByteCount);
	LogCmd(conn, '$', statbuf);

	StatusUpdate(conn, "(closed)");
	freeReaderSlot(conn->co_Desc->d_Slot);
	--NumReaders;
	/*
	 * Inform the main server that we are done with the descriptor
	 * by writing the DnsRes structure back to it, so the main server
	 * can track who from where is connecting to what and when that
	 * connection terminates.
	 */
	conn->co_Auth.dr_ByteCount = conn->co_TMBuf.mh_TotalBytes;
	SendMsg(TFd, conn->co_Desc->d_Fd, &conn->co_Auth);
    }

    FreeControl(conn);
    freePool(&conn->co_BufPool);
    freePool(&mpool);		/* includes Connection structure itself */
}
Exemple #2
0
BOOL ParseDirLine(Connection *Connect,BOOL AllFiles,FTPFileInfo* p)
{
	PROC(("ParseDirLine", "%p,%d", Connect, AllFiles))
	String        Line, Line1;
	FTPDirList    dl;
	FTPServerInfo si;

	while(true)
	{
		Connect->GetOutput(Line);

		if(!Line.Length())
			break;

		if(strstr(Line.c_str(),": Permission denied"))
		{
			WINPORT(SetLastError)(ERROR_ACCESS_DENIED);
			return FALSE;
		}

		if(Line.Length() < 20)
			continue;

		//Check contains skipped text
		static LPCSTR FTPMsg[] =
		{
			"data connection",
			"transfer complete",
			"bytes received",
			"DEVICE:[",
			"Total of "
		};
		BOOL Found = FALSE;

		for(size_t n = 0; n < ARRAYSIZE(FTPMsg); n++)
			if(strstr(Line.c_str(),FTPMsg[n]))
			{
				Found = TRUE;
				break;
			}

		if(Found) continue;

		//Check special skip strings
		if(StrCmp(Line.c_str(), "Directory ", 10) == 0 &&
		        strchr(Line.c_str()+10,'[') != NULL)
			continue;

		//Set start detect info
		memset(p, 0, sizeof(*p));
		si.ServerType = Connect->Host.ServerType;
		StrCpy(si.ServerInfo, Connect->SystemInfo, ARRAYSIZE(si.ServerInfo));
		//Use temp buffer
		Line1 = Line;
		//Detect
		WORD     idx;
		FTPType* tp = dl.GetType(Connect->Host.ServerType);

		if(Connect->Host.ServerType == FTP_TYPE_DETECT ||
		        Connect->Host.ServerType == FTP_TYPE_INVALID ||
		        tp == NULL)
		{
			idx = dl.DetectStringType(&si, Line.c_str(), Line.Length());

			if(idx == FTP_TYPE_INVALID || (tp=dl.GetType(idx)) == NULL)
			{
				LogCmd(Message("ParserDETECT: %s->%s [%s]", Parser2Str(Connect->Host.ServerType,&dl), Parser2Str(idx,&dl), Line1.c_str()), ldInt);

				if(Connect->Host.ServerType != FTP_TYPE_DETECT &&
				        Connect->Host.ServerType != FTP_TYPE_INVALID)
				{
					LogCmd(Message("ParserIGNORE: [%s]", Line1.c_str()), ldInt);
					Connect->AddCmdLine(Message("ParserIGNORE: [%s]", Line1.c_str()));
					continue;
				}

				BadFormat(Connect,Line1.c_str(),FALSE);
				break;
			}
			else
			{
				Log(("ParserDETECTED: %s->%s [%s]",Parser2Str(Connect->Host.ServerType,&dl),Parser2Str(idx,&dl),Line1.c_str()));
				Connect->Host.ServerType = idx;
			}
		}
		else
			idx = Connect->Host.ServerType;

		//Use temp buffer
		Line = Line1;
		Log(("toParse: %d,[%s], %d",Line.Length(),Line.c_str()));

		//Parse
		if(!tp->Parser(&si,p,Line.c_str(),Line.Length()))
		{
			LogCmd(Message("ParserFAIL: %s->%s [%s]",
			               Parser2Str(Connect->Host.ServerType,&dl),
			               Parser2Str(idx,&dl),
			               Line1.c_str()),
			       ldInt);
			Connect->AddCmdLine(Message("ParserFAIL: (%s) [%s]", Parser2Str(idx,&dl), Line1.c_str()));
			continue;
		}

		//Skip entryes
		char *CurName = FTP_FILENAME(p);

		if(p->FileType == NET_SKIP ||
		        !CurName[0] ||
		        StrCmp(CurName,".") == 0 ||
		        (!AllFiles && StrCmp(CurName,"..") == 0))
			continue;

		//Correct attrs
		if(p->FileType == NET_DIRECTORY ||
		        p->FileType == NET_SYM_LINK_TO_DIR)
			SET_FLAG(p->FindData.dwFileAttributes,FILE_ATTRIBUTE_DIRECTORY);

		if(p->FileType == NET_SYM_LINK_TO_DIR ||
		        p->FileType == NET_SYM_LINK)
			SET_FLAG(p->FindData.dwFileAttributes,FILE_ATTRIBUTE_REPARSE_POINT);

		//Convert name text
//		Connect->ToOEM(CurName);
		//OK
		return TRUE;
	}

	WINPORT(SetLastError)(ERROR_NO_MORE_FILES);
	return FALSE;
}
Exemple #3
0
void
NNFeedOverview(Connection *conn)
{
    int artLen;
    int l = 0;
    char *art = MBNormalize(&conn->co_ArtBuf, &artLen);
    char *line;
    int appr = 0;
    char ch;
    int err = 0;

    char *newsgroups = NULL;
    char *msgid = NULL;
    char *subject = NULL;
    char *date = NULL;
    char *xref = NULL;
    char *control = NULL;
    char *supers = NULL;	/* Supersedes */

    /*
     * Scan headers, look for Newsgroups: line, Subject:, Date:, From:, and
     * Message-Id:.  If any are missing, the article is bad.  If there is an
     * Xref: line, save that too and use it to calculate line numbers if 
     * Xref operation is enabled.
     *
     * We allow an LF-only line to terminate the headers as well as CR+LF,
     * because some news systems are totally broken.
     */

    for (line = art; line < art + artLen; line += l + 1) {
	for (l = line - art; l < artLen; ++l) {
	    if (art[l] == '\n') {
		if (l + 1 >= artLen || 		/* past end of article	*/
		    l == line - art || 		/* blank line		*/
		    (art[l+1] != ' ' && art[l+1] != '\t')  /* !header ext */
		) {
		    break;
		}
	    }
	}
	l -= line - art;

	ch = tolower(*line);

	if (l == 0 || (l == 1 && line[0] == '\r')) {
	    /* out of headers */
	    break;
	} else if (ch == 'n' && strncasecmp(line, "Newsgroups:", 11) == 0) {
	    newsgroups = zallocStrTrim2(&conn->co_MemPool, ',', line + 11, l - 11);
	} else if (ch == 'm' && strncasecmp(line, "Message-ID:", 11) == 0) {
	    msgid = zallocStrTrim2(&conn->co_MemPool, 0, line + 11, l - 11);
	} else if (ch == 's' && strncasecmp(line, "Subject:", 8) == 0) {
	    subject = zallocStrTrim2(&conn->co_MemPool, 0, line + 8, l - 8);
	} else if (ch == 'd' && strncasecmp(line, "Date:", 5) == 0) {
	    date = zallocStrTrim2(&conn->co_MemPool, 0, line + 5, l - 5);
	} else if (ch == 'x' && strncasecmp(line, "Xref:", 5) == 0) {
	    xref = zallocStrTrim2(&conn->co_MemPool, ',', line + 5, l - 5);
	} else if (ch == 'c' && strncasecmp(line, "Control:", 8) == 0) {
	    control = zallocStrTrim2(&conn->co_MemPool, 0, line + 8, l - 8);
	} else if (ch == 's' && strncasecmp(line, "Supersedes:", 11) == 0) {
	    supers = zallocStrTrim2(&conn->co_MemPool, 0, line + 11, l - 11);
	} else if (ch == 'a' && strncasecmp(line, "Approved:", 9) == 0) {
	    appr = 1;
	}
    }

    if (conn->co_Flags & COF_POSTTOOBIG) {
	conn->co_Auth.dr_PostFailCount++;
	if (conn->co_Flags & COF_IHAVE) {
	    MBLogPrintf(conn, &conn->co_TMBuf, "437 Rejected, too big\r\n");
	} else {
	    MBLogPrintf(conn, &conn->co_TMBuf, "439 %s too big\r\n",  conn->co_IHaveMsgId);
	}
	conn->co_Flags &= ~COF_POSTTOOBIG;
    } else if (newsgroups == NULL || msgid == NULL || subject == NULL || 
	date == NULL || strcmp(msgid, "<>") == 0
    ) {
	/*
	 * failure
	 */
	conn->co_Auth.dr_PostFailCount++;
	if (conn->co_Flags & COF_IHAVE) {
	    MBLogPrintf(conn, &conn->co_TMBuf, "437 Rejected, headers missing\r\n");
	} else {
	    MBLogPrintf(conn, &conn->co_TMBuf, "439 %s\r\n",  conn->co_IHaveMsgId);
	}
    } else if (conn->co_ByteCounter == 0.0 && conn->co_BytesHeader == 0) {
	conn->co_Auth.dr_PostFailCount++;
	if (conn->co_Flags & COF_IHAVE) {
	    MBLogPrintf(conn, &conn->co_TMBuf, "437 Rejected, Bytes header missing for header-only feed\r\n");
	} else {
	    MBLogPrintf(conn, &conn->co_TMBuf, "439 %s headerOnlyFeed requires Bytes header\r\n",  conn->co_IHaveMsgId);
	}
    } else if (FindCancelCache(msgid) == 0) {
	char logbuf[1024];
	conn->co_Auth.dr_PostFailCount++;
	snprintf(logbuf, sizeof(logbuf), "%s cancel cache", msgid);
	LogCmd(conn, '-', logbuf);
	if (DRIncomingLogPat != NULL)
	    LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf);
	if (conn->co_Flags & COF_IHAVE) {
	    MBLogPrintf(conn, &conn->co_TMBuf, "437 Article Already Cancelled\r\n");
	} else {
	    MBLogPrintf(conn, &conn->co_TMBuf, "439 %s Article Already Cancelled\r\n",  conn->co_IHaveMsgId);
	}
    } else {
	/*
	 * write out overview information
	 */
	char *group;
	char *ngroup = NULL;
	ArtNumAss	*ANABase = NULL;


	/*
	 * if it is a control message, we don't really care what the newsgroups
	 * line says.  instead, we cobble up "control.<type>" or just "control"
	 */

	if (conn->co_Flags & COF_WASCONTROL) {
	    char cmsgtype[64];
	    char *cptr;

	    cptr = control;
	    while (*cptr == ' ' || *cptr == '\t') {
		cptr++;
	    }
	    snprintf(cmsgtype, sizeof(cmsgtype), "control%s%s", *cptr ? "." : "", cptr);
	    if (((cptr = strchr(cmsgtype, ' '))) || ((cptr = strchr(cmsgtype, '\t')))) {
		*cptr = '\0';
	    }
	    zfreeStr(&conn->co_MemPool, &newsgroups);
	    newsgroups = zallocStr(&conn->co_MemPool, cmsgtype);
	}
	if (DebugOpt)
	    printf("Feed overview %s %s\n", msgid, newsgroups);

	/*
	 * pass 1 - assign article numbers
	 */

	for (group = newsgroups; *group; group = ngroup) {
	    char c;
	    char whspc = 0;
	    char *whspptr;

	    /* Strip leading spaces */
	    while (*group == ' ' || *group == '\t') {
		group++;
	    }
	    if (! *group) {
		break;
	    }

	    for (ngroup = group; *ngroup && *ngroup != ','; ++ngroup)
		;
	    c = *ngroup;
	    *ngroup = 0;

	    /*
	     * Skip groups with names that are too long
	     */
	    if (ngroup - group > MAXGNAME)
		continue;

	    /* Strip trailing space or tab from group name */
	    whspptr = strpbrk(group, " \t");
	    if (whspptr) {
		whspc = *whspptr;
		*whspptr = 0;
	    }

	    AssignArticleNo(conn, &ANABase, group, xref, appr, art, artLen, msgid);

	    /* Repair string back to its former state */
	    if (whspptr) {
		*whspptr = whspc;
	    }

	    *ngroup = c;

	    if (*ngroup == ',')
		++ngroup;
	}

	/*
	 * Supersedes is allowed on non-control messages.  We execute the
	 * cancel AND post the article.  Note: we do not allow supersedes
	 * on Control: messages. (XXX is this still true with the new logic? JG)
	 */

	if (supers) {
	    if (DebugOpt)
		printf("has Supersedes: %s %s\n", msgid, newsgroups);
	    ExecuteSupersedes(conn, supers, art, artLen);
	}

	err = 0;
	for (group = newsgroups; *group; group = ngroup) {
	    char c;
	    char whspc = 0;
	    char *whspptr;

	    for (ngroup = group; *ngroup && *ngroup != ','; ++ngroup)
		;
	    c = *ngroup;
	    *ngroup = 0;

	    /*
	     * Skip groups with names that are too long
	     */
	    if (ngroup - group > MAXGNAME)
		continue;

	    /* Strip trailing space or tab from group name */
	    whspptr = strpbrk(group, " \t");
	    if (whspptr) {
		whspc = *whspptr;
		*whspptr = 0;
	    }

	    err += WriteOverview(conn, ANABase, group, xref, art, artLen, msgid);

	    /* Repair string back to its former state */
	    if (whspptr) {
		*whspptr = whspc;
	    }

	    *ngroup = c;
	    if (*ngroup == ',')
		++ngroup;
	}
	while (ANABase) {
	    ArtNumAss *an = ANABase;
	    ANABase = an->an_Next;
	    zfree(&conn->co_MemPool, an, sizeof(ArtNumAss));
	}
	if (conn->co_Flags & COF_WASCONTROL) {
	    if (DebugOpt)
		printf("Control message: %s %s\n", msgid, newsgroups);
	    LogCmd(conn, 'c', control);
	    if (DRIncomingLogPat != NULL)
		LogIncoming("%s c %s %s", conn->co_Auth.dr_Host,
							msgid, control);
	    ExecuteControl(conn, control, art, artLen);
	}

	if (!err) {
	    conn->co_Auth.dr_PostCount++;
	    if (conn->co_Flags & COF_IHAVE) {
		MBLogPrintf(conn, &conn->co_TMBuf, "235\r\n");
	    } else {
		MBLogPrintf(conn, &conn->co_TMBuf, "239 %s\r\n",  conn->co_IHaveMsgId);
	    }
	}
    }

    zfreeStr(&conn->co_MemPool, &newsgroups);
    zfreeStr(&conn->co_MemPool, &msgid);
    zfreeStr(&conn->co_MemPool, &subject);
    zfreeStr(&conn->co_MemPool, &date);
    zfreeStr(&conn->co_MemPool, &xref);
    zfreeStr(&conn->co_MemPool, &control);
    zfreeStr(&conn->co_MemPool, &conn->co_IHaveMsgId);

    MBFree(&conn->co_ArtBuf);
    NNCommand(conn);
}
Exemple #4
0
int
WriteOverview(Connection *conn, ArtNumAss *an, const char *group, const char *xref, const char *art, int artLen, const char *msgid)
{
    artno_t artNo = 0;
    const char *body;
    char *xtmp = NULL;
    int xtmpLen = 16 + strlen(conn->co_Auth.dr_VServerDef->vs_ClusterName);
    char logbuf[1024];
    int err = 0;

    /*
     * Locate article number assignment
     */
    {
	ArtNumAss *scan;

	for (scan = an; scan; scan = scan->an_Next) {
	    if (scan->an_GroupName == group) {
		artNo = scan->an_ArtNo;
	    }
	    xtmpLen += scan->an_GroupLen + 15;
	}
    }

    if (artNo == 0)
	return(0);

    /*
     * XXX We should find some way to aggregate these into one log entry.
     */

    snprintf(logbuf, sizeof(logbuf), "%s %s:%lld", msgid, group, artNo);

    /*
     * Locate start of body (we may have to append our own Xref: line)
     */

    {
	int l;
	int lnl = 1;

	for (l = 0; l < artLen; ++l) {
	    /*
	     * blank line terminates headers
	     */
	    if (art[l] == '\r' && (l + 1 >= artLen || art[l+1] == '\n')) {
		if (lnl)
		    break;
	    }
	    lnl = 0;
	    if (art[l] == '\n')
		lnl = 1;
	}
	body = art + l;
    }

    /*
     * Write overview record.
     */

    {
	off_t pos;
	OverInfo *ov;
	const OverArt *oa;
	hash_t hv = hhash(msgid);
	int actLen = 0;
	int iovLen = 0;
	int prealloc_ov, prealloc_oh;
	struct iovec iov[3];

	if ((ov = GetOverInfo(group)) == NULL) {
	    logit(LOG_ERR, "Error in GetOverInfo(%s) msgid=%s", group, msgid);
	    LogCmd(conn, '-', logbuf);
	    if (DRIncomingLogPat != NULL)
		LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf);
	    MBLogPrintf(conn, &conn->co_TMBuf, "400 Error writing data\r\n");
	    NNTerminate(conn);
	    return(1);
	}
	prealloc_ov = (ov->ov_MaxArts * sizeof(OverArt)) / 8;
	prealloc_oh = (1024 * ov->ov_Head->oh_DataEntries) / 8;

	if (MakeOverHFile(ov, artNo, 1) == NULL) {
	    logit(LOG_ERR, "Error in MakeOverHFile() msgid=%s", msgid);
	    LogCmd(conn, '-', logbuf);
	    if (DRIncomingLogPat != NULL)
		LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf);
	    MBLogPrintf(conn, &conn->co_TMBuf, "400 Error writing data\r\n");
	    NNTerminate(conn);
	    return(1);
	}

	hflock(ov->ov_HCache->od_HFd, 0, XLOCK_EX);
	pos = lseek(ov->ov_HCache->od_HFd, 0L, 2);

	errno = 0;

	if (xref) {
	    iov[0].iov_base = (void *)art;
	    iov[0].iov_len = artLen + 1;
	    iovLen = 1;
	} else {
	    ArtNumAss *scan;
	    int soff;
	    
	    xtmp = zalloc(&conn->co_MemPool, xtmpLen);
	    sprintf(xtmp, "Xref: %s", DOpts.ReaderXRefHost);
	    soff = strlen(xtmp);
		
	    for (scan = an; scan; scan = scan->an_Next) {
		xtmp[soff++] = ' ';
		memcpy(xtmp + soff, scan->an_GroupName, scan->an_GroupLen);
		soff += scan->an_GroupLen;
		sprintf(xtmp + soff, ":%lld", scan->an_ArtNo);
		soff += strlen(xtmp + soff);
	    }
	    sprintf(xtmp + soff, "\r\n");
	    soff += 2;
	    iov[0].iov_base = (void *)art;
	    iov[0].iov_len = body - art;
	    iov[1].iov_base = xtmp;
	    iov[1].iov_len = soff;
	    iov[2].iov_base = (void *)body;
	    iov[2].iov_len = (art + artLen + 1) - body;
	    iovLen = 3;
	}

	if (art[0] == 0)
	    logit(LOG_ERR, "Warning: art[0] is NIL! %s", xtmp);
		
	{
	    int i;
	    for (i = 0; i < iovLen; ++i)
		actLen += iov[i].iov_len;
	}

	if (DOpts.ReaderXRefSlaveHost && 
	    (oa = GetOverArt(ov, artNo, NULL)) != NULL &&
	    oa->oa_MsgHash.h1 == hv.h1 &&
	    oa->oa_MsgHash.h2 == hv.h2 &&
	    OA_ARTNOEQ(artNo, oa->oa_ArtNo)
	) {
	    /*
	     * We can detect duplicate articles in XRef slave mode.  If 
	     * we see one, do not do anything.
	     */
	    LogCmd(conn, 'd', logbuf);
	    if (DRIncomingLogPat != NULL)
		LogIncoming("%s d %s%s", conn->co_Auth.dr_Host, "", logbuf);
	    ; /* EMPTY */
	} else if (DOpts.ReaderXOverMode == 0) {
	    /*
	     * Do not write xover info at all.  This mode is not really
	     * supported by the reader but may eventually be supported
	     * in 100% nntp-cache mode if/when we develop it.
	     */
	    logit(LOG_INFO, "ReaderXOverMode0 (%lld:%s)", artNo, msgid);
	    LogCmd(conn, 'm', logbuf);
	    if (DRIncomingLogPat != NULL)
		LogIncoming("%s m %s%s", conn->co_Auth.dr_Host, "", logbuf);
	    ; /* EMPTY */
	} else if (
	    DOpts.ReaderXOverMode == 2 ||
	    (FilePreAllocSpace(ov->ov_HCache->od_HFd, pos,
	     prealloc_oh, iovLen) == 0 &&
	     writev(ov->ov_HCache->od_HFd, iov, iovLen) == actLen)
	) {
	    /*
	     * Our write of the overview data succeeded or we were asked not
	     * to write out the overview data.  Write out the overview 
	     * article record.
	     */
	    OverArt ovart = { 0 };
	    off_t ovpos = 0;

	    hflock(ov->ov_OFd, 0, XLOCK_EX);

	    (void)GetOverArt(ov, artNo, &ovpos);

	    ovart.oa_ArtNo = OA_ARTNOSET(artNo);
	    if (DOpts.ReaderXOverMode == 2)
		ovart.oa_SeekPos = -1;
	    else
		ovart.oa_SeekPos = pos;
	    ovart.oa_Bytes = actLen - 1;	/* do not include \0 */
	    ovart.oa_MsgHash = hv;
	    ovart.oa_TimeRcvd = (int)time(NULL);
	    ovart.oa_ArtSize = (conn->co_ByteCounter > 0.0 ? conn->co_ByteCounter : conn->co_BytesHeader);

	    lseek(ov->ov_OFd, ovpos, 0);
	    FilePreAllocSpace(ov->ov_OFd, ovpos, prealloc_ov, sizeof(ovart));
	    write(ov->ov_OFd, &ovart, sizeof(ovart));
	    hflock(ov->ov_OFd, 0, XLOCK_UN);
	    LogCmd(conn, '+', logbuf);
	    if (DRIncomingLogPat != NULL)
		LogIncoming("%s + %s%s", conn->co_Auth.dr_Host, "", logbuf);
	} else {
	    ftruncate(ov->ov_HCache->od_HFd, pos);
	    logit(LOG_ERR, "error writing overview data file for %s", group);
	    LogCmd(conn, '-', logbuf);
	    if (DRIncomingLogPat != NULL)
		LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf);
	    MBLogPrintf(conn, &conn->co_TMBuf, "400 Error writing data\r\n");
	    NNTerminate(conn);
	    err = 1;
	}
	hflock(ov->ov_HCache->od_HFd, 0, XLOCK_UN);
	PutOverInfo(ov);
    }
    if (xtmp)
	zfree(&conn->co_MemPool, xtmp, xtmpLen);
    return(err);
}
Exemple #5
0
void
AssignArticleNo(Connection *conn, ArtNumAss **pan, const char *group, const char *xref, int approved, const char *art, int artLen, const char *msgid)
{
    const char *rec;
    int recLen;
    int groupLen = strlen(group);
    artno_t activeArtBeg;
    artno_t activeArtEnd;
    int aabegchanged = 0;
    int foundXRef = 0;
    int ts;
    char aabegbuf[20];
    char aaendbuf[20];
    artno_t artNo;
    char logbuf[1024];

    if (DOpts.ReaderAutoAddToActive) {
	/*
	 * locate group in active file and lock, create if it does not exist
	 * You will have to manually add a GD, M, and fix S as appropriate
	 * through some external process, if you use this.
	 */
	if ((rec = KPDBReadRecord(KDBActive, group, KP_LOCK, &recLen)) == NULL) {
	    if (ValidGroupName(group) < 0) {
		/* logit(LOG_ERR, "group %s illegal", group); */
	    } else {
		char tsBuf[64];

		KPDBWrite(KDBActive, group, "NB", "0000000001", KP_LOCK);
		KPDBWrite(KDBActive, group, "NE", "0000000000", KP_LOCK_CONTINUE);
		sprintf(tsBuf, "%08x", (int)time(NULL));
		KPDBWrite(KDBActive, group, "CTS", tsBuf, KP_LOCK_CONTINUE);
		KPDBWrite(KDBActive, group, "LMTS", tsBuf, KP_LOCK_CONTINUE);   
		KPDBWrite(KDBActive, group, "S", "y", KP_UNLOCK);
	}
            if ((rec = KPDBReadRecord(KDBActive, group, KP_LOCK, &recLen)) == NULL) {
		snprintf(logbuf, sizeof(logbuf), "%s %s not in dactive", msgid, group);
		LogCmd(conn, '-', logbuf);
		if (DRIncomingLogPat != NULL)
		    LogIncoming("%s - %s%s", conn->co_Auth.dr_Host,
							"", logbuf);
		return;
	    }
	}
    } else {
	/*
	 * locate group in active file and lock
	 */
	if ((rec = KPDBReadRecord(KDBActive, group, KP_LOCK, &recLen)) == NULL) {
	    snprintf(logbuf, sizeof(logbuf), "%s %s not in dactive", msgid, group);
	    LogCmd(conn, '-', logbuf);
	    if (DRIncomingLogPat != NULL)
		LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf);
	    return;
	}
    }

    /*
     * silently drop postings to moderated groups that do not have an
     * approved header.
     */

    if (approved == 0) {
	int flagsLen;
	const char *flags = KPDBGetField(rec, recLen, "S", &flagsLen, "y");

	while (flagsLen > 0) {
	    if (*flags == 'm') {
		KPDBUnlock(KDBActive, rec);
		snprintf(logbuf, sizeof(logbuf), "%s %s unapproved", msgid, group);
		LogCmd(conn, '-', logbuf);
		if (DRIncomingLogPat != NULL)
		    LogIncoming("%s - %s%s", conn->co_Auth.dr_Host,
							"", logbuf);
		return;
	    }
	    --flagsLen;
	    ++flags;
	}
    }

    /*
     * assign article number.  Locate Xref: line if Xref's are enabled
     */

    activeArtEnd = strtoll(KPDBGetField(rec, recLen, "NE", NULL, "-1"), NULL,10);
    activeArtBeg = strtoll(KPDBGetField(rec, recLen, "NB", NULL, "-1"), NULL,10);
    ts = (int)strtoul(KPDBGetField(rec, recLen, "LMTS", NULL, "0"), NULL, 16);
    artNo = activeArtEnd + 1;

    if (xref) {
	const char *test;

	for (test = strchr(xref, ' '); test; test = strchr(test, ' ')) {
	    ++test;
	    if (strncmp(test, group, groupLen) == 0 && test[groupLen] == ':') {
		artNo = strtoll(test + groupLen + 1, NULL, 10);
		foundXRef = 1;
		break;
	    }
	}
    }

    /*
     * If we did not find an XRef entry and we are in xref-slave mode,
     * drop the newsgroup on the floor.
     */

    if (foundXRef == 0 && DOpts.ReaderXRefSlaveHost != NULL) {
	KPDBUnlock(KDBActive, rec);
	snprintf(logbuf, sizeof(logbuf), "%s %s no valid xref present in slave mode", msgid, group);
	LogCmd(conn, '-', logbuf);
	if (DRIncomingLogPat != NULL)
	    LogIncoming("%s - %s%s", conn->co_Auth.dr_Host, "", logbuf);
	return;
    }

    if (artNo < 1)
	artNo = 1;

    if (activeArtEnd < artNo) {
	activeArtEnd = artNo;
	if (activeArtBeg > activeArtEnd) {
	    activeArtBeg = activeArtEnd;
	    aabegchanged = 1;
	}
    } else if (activeArtBeg > artNo) {
	activeArtBeg = artNo;
	aabegchanged = 1;
	if (activeArtEnd < activeArtBeg)
	    activeArtEnd = activeArtBeg;
    } else if (activeArtBeg > activeArtEnd) {
	activeArtBeg = activeArtEnd = artNo;
	aabegchanged = 1;
    }

    {
	int nts = (int)time(NULL);
	if (nts != ts) {
	    char tsBuf[64];
	    sprintf(tsBuf, "%08x", nts);
	    KPDBWrite(KDBActive, group, "LMTS", tsBuf, KP_LOCK_CONTINUE);
	}
    }

    sprintf(aabegbuf, "%010lld", activeArtBeg);
    sprintf(aaendbuf, "%010lld", activeArtEnd);

    if (aabegchanged)
	KPDBWrite(KDBActive, group, "NB", aabegbuf, KP_LOCK_CONTINUE);	/* continuing lock */
    KPDBWrite(KDBActive, group, "NE", aaendbuf, KP_UNLOCK);		/* and unlock 	   */

    {
	ArtNumAss *an = zalloc(&conn->co_MemPool, sizeof(ArtNumAss));
	an->an_Next = *pan;
	*pan = an;
	an->an_GroupName = group;
	an->an_GroupLen = strlen(group);
	an->an_ArtNo = artNo;
    }
}
Exemple #6
0
void
NNCommand2(Connection *conn)
{
    char *ptr;
    char *cmd;
    char *buf;
    Command *scan;
    int len;

    conn->co_Func = NNCommand2;
    conn->co_State = "waitcmd";

    /*
     * we have to be careful in regards to recursive operation, nor do
     * we want one descriptor to hog the process.  We can't set RFds
     * because the next command may already be entirely loaded into an
     * MBuf so setting RFds may not unblock us.  Instead, we set WFds
     * which basically forces a wakeup at some point in the future.
     */

    if (conn->co_FCounter) {
	FD_SET(conn->co_Desc->d_Fd, &WFds);
	/*
	 * if the other side closed the connection, select() is
	 * not going to wake up for write(!) so set RFds too.
	 */
	if (conn->co_TMBuf.mh_WError)
	    FD_SET(conn->co_Desc->d_Fd, &RFds);
	return;
    }
    ++conn->co_FCounter;

    /*
     * if there is still output pending, do not process the next
     * command.
     */
    if (conn->co_TMBuf.mh_Bytes > 0 && !conn->co_TMBuf.mh_WError)
	return;

    /*
     * get command
     */

    if ((len = MBReadLine(&conn->co_RMBuf, &buf)) == 0) {
	StatusUpdate(conn, "(idle)");
	return;
    }

    conn->co_ByteCountType = DRBC_NONE;

    /*
     * check EOF
     */

    if (len < 0 || conn->co_TMBuf.mh_WError) {
	NNTerminate(conn);
	return;
    }

    /*
     * strip CR LF
     */

    ptr = buf;

    if (len > 1 && ptr[len-2] == '\r')
	ptr[len-2] = 0;

    if (DebugOpt)
	printf("command: %s\n", ptr);

    if (strncasecmp(ptr, "authinfo pass ", 14)) {
        LogCmd(conn, '<', ptr);
    } else {
        LogCmd(conn, '<', "authinfo pass **unlogged**");
    }

    if (conn->co_Auth.dr_Flags & DF_USEPROXIED) {
      struct sockaddr_in sin;
      char *pt = NULL;

      if (strncasecmp(ptr, "proxied ", 8) || ! ((pt = strrchr(ptr, ':')))) {
          MBLogPrintf(conn,
              &conn->co_TMBuf,
              "400 %s: Proxy authentication failure.\r\n",
              conn->co_Auth.dr_VServerDef->vs_HostName
          );
          NNTerminate(conn);
      }

      *pt++ = '\0';
      ptr += 8;

      bzero((void *)&sin, sizeof(&sin));
      sin.sin_family = AF_INET;
      sin.sin_port = htons(atoi(pt));
      sin.sin_addr.s_addr = inet_addr(ptr);
      bcopy(&sin, &conn->co_Auth.dr_Addr, sizeof(conn->co_Auth.dr_Addr));

      conn->co_Auth.dr_Flags &= ~DF_USEPROXIED;
      conn->co_Auth.dr_ResultFlags = DR_REQUIRE_DNS;
      return;
    }

    /*
     * extract command (note: StatusUpdate() will limit the line length)
     */

    StatusUpdate(conn, "%s", ptr);

    if ((cmd = parseword(&ptr, " \t")) == NULL) {
	NNCommand(conn);
	return;
    }
    {
	int i;

	for (i = 0; cmd[i]; ++i)
	    cmd[i] = tolower((int)(unsigned char)cmd[i]);
    }

    /*
     * Locate and execute command
     */

    for (scan = &Cmds[0]; scan < &Cmds[arysize(Cmds)]; ++scan) {
	if (strcmp(cmd, scan->cmd_Name) == 0) {
	    if (conn->co_Flags & COF_SERVER) {
		if (scan->cmd_Flags & CMDF_SERVER) {
		    if ((conn->co_Auth.dr_Flags & DF_FEEDONLY) == 0)
			break;
		    if ((scan->cmd_Flags & CMDF_NOTFEEDONLY) == 0)
			break;
		}
	    } else {
		if (scan->cmd_Flags & CMDF_READER)
		    break;
	    }
	}
    }
    if (scan < &Cmds[arysize(Cmds)]) {
	if ((scan->cmd_Flags & CMDF_AUTH) &&
	    (conn->co_Auth.dr_Flags & DF_AUTHREQUIRED)
	) {
	    MBLogPrintf(conn, &conn->co_TMBuf, "480 Authentication required for command\r\n");
	    NNCommand(conn);
	} else {
	    conn->co_ByteCountType = scan->cmd_DRBC_Type;
	    scan->cmd_Func(conn, &ptr);
	}
    } else {
	NNUnknownCommand(conn);
    }
}