Пример #1
0
// check data received from ICAP server and interpret as virus name & return value
int icapinstance::doScan(Socket & icapsock, HTTPHeader * docheader, const char* object, unsigned int objectsize, NaughtyFilter * checkme)
{
	char *data = new char[8192];
	try {
		String line;
		int rc = icapsock.getLine(data, 8192, o.content_scanner_timeout);
		if (rc == 0)
			return ICAP_NODATA;
		line = data;
#ifdef DGDEBUG
		std::cout << "reply from icap: " << line << std::endl;
#endif
		// reply is of the format:
		// ICAP/1.0 204 No Content Necessary (etc)

		String returncode(line.after(" ").before(" "));

		if (returncode == "204") {
#ifdef DGDEBUG
			std::cerr << "ICAP says clean!" << std::endl;
#endif
			delete[]data;
			return DGCS_CLEAN;
		} else if (returncode == "100") {
#ifdef DGDEBUG
			std::cerr << "ICAP says continue!" << std::endl;
#endif
			// discard rest of headers (usually just a blank line)
			// this is so we are in the right place in the data stream to
			// call doScan() again later, because people like Symantec seem
			// to think sending code 100 then code 204 one after the other
			// is not an abuse of the ICAP specification.
			while (icapsock.getLine(data, 8192, o.content_scanner_timeout) > 0) {
				if (data[0] == 13)
					break;
			}
			delete[]data;
			return ICAP_CONTINUE;
		}
		else if (returncode == "200") {
#ifdef DGDEBUG
			std::cerr << "ICAP says maybe not clean!" << std::endl;
#endif
			while (icapsock.getLine(data, 8192, o.content_scanner_timeout) > 0) {
				if (data[0] == 13)	// end marker
					break;
				line = data;
				// Symantec's engine gives us the virus name in the ICAP headers
				if (supportsXIF && line.startsWith("X-Infection-Found")) {
#ifdef DGDEBUG
					std::cout << "ICAP says infected! (X-Infection-Found)" << std::endl;
#endif
					lastvirusname = line.after("Threat=").before(";");
					delete[]data;
					
					blockFile(NULL,NULL,checkme);
					return DGCS_INFECTED;
				}
			}
			// AVIRA's Antivir gives us 200 in all cases, so
			// - unfortunately - we must pay attention to the encapsulated
			// header/body.
			if (needsBody) {
				// grab & compare the HTTP return code from modified response
				// if it's been modified, assume there's an infection
				icapsock.getLine(data, 8192, o.content_scanner_timeout);
				line = data;
#ifdef DGDEBUG
				std::cout << "Comparing original return code to modified:" << std::endl << docheader->header.front() << std::endl << line << std::endl;
#endif
				int respmodReturnCode = line.after(" ").before(" ").toInteger();
				if (respmodReturnCode != docheader->returnCode()) {
#ifdef DGDEBUG
					std::cerr << "ICAP says infected! (returned header comparison)" << std::endl;
#endif
					delete[] data;
					lastvirusname = "Unknown";

					blockFile(NULL,NULL,checkme);
					return DGCS_INFECTED;
				}
				// ok - headers were identical, so look at encapsulated body
				// discard the rest of the encapsulated headers
				while (icapsock.getLine(data, 8192, o.content_scanner_timeout) > 0) {
					if (data[0] == 13)
						break;
				}
				// grab body chunk size
#ifdef DGDEBUG
				std::cout << "Comparing original body data to modified" << std::endl;
#endif
				icapsock.getLine(data, 8192, o.content_scanner_timeout);
				line = data;
				int bodysize = line.hexToInteger();
				// get, say, the first 100 bytes and compare them to what we
				// originally sent to see if it has been modified
				unsigned int chunksize = (bodysize < 100) ? bodysize : 100;
				if (chunksize > objectsize)
					chunksize = objectsize;
				icapsock.readFromSocket(data, chunksize, 0, o.content_scanner_timeout);
				if (memcmp(data, object, chunksize) == 0) {
#ifdef DGDEBUG
					std::cerr << "ICAP says clean!" << std::endl;
#endif
					delete[]data;
					return DGCS_CLEAN;
				} else {
#ifdef DGDEBUG
					std::cerr << "ICAP says infected! (body byte comparison)" << std::endl;
#endif
					delete[] data;
					lastvirusname = "Unknown";

					blockFile(NULL,NULL,checkme);
					return DGCS_INFECTED;
				}
			}
			// even if we don't find an X-Infection-Found header,
			// the file is still infected!
#ifdef DGDEBUG
			std::cerr << "ICAP says infected! (no further tests)" << std::endl;
#endif
			delete[] data;
			lastvirusname = "Unknown";

			blockFile(NULL,NULL,checkme);
			return DGCS_INFECTED;
		}
		else if (returncode == "404") {
#ifdef DGDEBUG
			std::cerr << "ICAP says no such service!" << std::endl;
#endif
			lastmessage = "ICAP reports no such service";
			syslog(LOG_ERR, "ICAP reports no such service; check your server URL");
			delete[]data;
			return DGCS_SCANERROR;
		} else {
#ifdef DGDEBUG
			std::cerr << "ICAP returned unrecognised response code: " << returncode << std::endl;
#endif
			lastmessage = "ICAP returned unrecognised response code.";
			syslog(LOG_ERR, "ICAP returned unrecognised response code: %s", returncode.toCharArray());
			delete[]data;
			return DGCS_SCANERROR;
		}
		delete[]data;
	}
	catch(std::exception & e) {
#ifdef DGDEBUG
		std::cerr << "Exception getting reply from ICAP: " << e.what() << std::endl;
#endif
		lastmessage = "Exception getting reply from ICAP.";
		syslog(LOG_ERR, "Exception getting reply from ICAP: %s", e.what());
		delete[]data;
		return DGCS_SCANERROR;
	}
	// it is generally NOT a good idea, when using virus scanning,
	// to continue as if nothing went wrong by default!
	return DGCS_SCANERROR;
}
Пример #2
0
// no need to replace the inheritied scanMemory() which just calls scanFile()
// there is no capability to scan memory with kavdscan as we pass it
// a file name to scan.  So we save the memory to disk and pass that.
// Then delete the temp file.
int kavdinstance::scanFile(HTTPHeader *requestheader, HTTPHeader *docheader, const char *user, int filtergroup,
    const char *ip, const char *filename, NaughtyFilter *checkme, const String *disposition, const String *mimetype)
{
    lastvirusname = lastmessage = "";
    // mkstemp seems to only set owner permissions, so our AV daemon won't be
    // able to read the file, unless it's running as the same user as us. that's
    // not usually very convenient. so instead, just allow group read on the
    // file, and tell users to make sure the daemongroup option is friendly to
    // the AV daemon's group membership.
    // chmod can error with EINTR, ignore this?
    if (chmod(filename, S_IRGRP | S_IRUSR) != 0) {
        syslog(LOG_ERR, "Could not change file ownership to give kavd read access: %s", strerror(errno));
        return DGCS_SCANERROR;
    };
    String command("SCAN bPQRSTUW ");
    if (pathprefix.length()) {
        String fname(filename);
        command += fname.after(pathprefix.toCharArray());
    } else {
        command += filename;
    }
    command += "\r\n";
#ifdef DGDEBUG
    std::cerr << "kavdscan command:" << command << std::endl;
#endif
    UDSocket stripedsocks;
    if (stripedsocks.getFD() < 0) {
        syslog(LOG_ERR, "%s", "Error creating socket for talking to kavdscan");
        return DGCS_SCANERROR;
    }
    if (stripedsocks.connect(udspath.toCharArray()) < 0) {
        syslog(LOG_ERR, "%s", "Error connecting to kavdscan socket");
        stripedsocks.close();
        return DGCS_SCANERROR;
    }
    char *buff = new char[4096];
    memset(buff, 0, 4096);
    int rc;
    try {
        // read kaspersky kavdscan (AV Enging Server) - format: 2xx greeting
        rc = stripedsocks.getLine(buff, 4096, o.content_scanner_timeout);
    } catch (std::exception &e) {
    }
    if (buff[0] != '2') {
        delete[] buff;
        stripedsocks.close();
        syslog(LOG_ERR, "%s", "kavdscan did not return ok");
        return DGCS_SCANERROR;
    }
    try {
        stripedsocks.writeString(command.toCharArray());
    } catch (std::exception &e) {
        delete[] buff;
        stripedsocks.close();
        syslog(LOG_ERR, "%s", "unable to write to kavdscan");
        return DGCS_SCANERROR;
    }
    try {
        rc = stripedsocks.getLine(buff, 4096, o.content_scanner_timeout);
    } catch (std::exception &e) {
        delete[] buff;
        stripedsocks.close();
        syslog(LOG_ERR, "%s", "Error reading kavdscan socket");
        return DGCS_SCANERROR;
    }
    String reply(buff);
#ifdef DGDEBUG
    std::cout << "Got from kavdscan:" << reply << std::endl;
#endif
    if (reply[0] == '2') { // clean
#ifdef DGDEBUG
        std::cerr << "kavdscan - clean" << std::endl;
#endif
        delete[] buff;
        stripedsocks.close();
        return DGCS_CLEAN;
    }
    if (reply.startsWith("322")) { // infected
        // patch to handle multiple virii in kavd response
        // originally submitted by cahya <*****@*****.**>
        while (reply[0] != '2' && rc != 0) {
            reply.removeWhiteSpace();
            lastvirusname = lastvirusname + " " + reply.after("322-").before(" ");
            try {
                rc = stripedsocks.getLine(buff, 4096, o.content_scanner_timeout);
            } catch (std::exception &e) {
                delete[] buff;
                stripedsocks.close();
                syslog(LOG_ERR, "%s", "Error reading kavdscan socket");
                return DGCS_SCANERROR;
            }
            reply = buff;
#ifdef DGDEBUG
            std::cout << "Got from kavdscan:" << reply << std::endl;
#endif
        }
        std::cout << "lastvirusname: " << lastvirusname << std::endl;
        delete[] buff;
        stripedsocks.close();

        // format: 322 nastyvirus blah
        blockFile(NULL, NULL, checkme);
        return DGCS_INFECTED;
    }
    delete[] buff;
    stripedsocks.close();
    // must be an error then
    lastmessage = reply;
    return DGCS_SCANERROR;
}