Exemple #1
0
/* Sends a proper scan request to clamd and parses its replies
 * This is used only in non IDSESSION mode
 * Returns the number of infected files or -1 on error
 * NOTE: filename may be NULL for STREAM scantype. */
int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors) {
    int infected = 0, len = 0, beenthere = 0;
    char *bol, *eol;
    struct RCVLN rcv;
    STATBUF sb;

    if(filename && chkpath(filename))
	return 0;
    recvlninit(&rcv, sockd);

    switch(scantype) {
    case MULTI:
    case CONT:
    case ALLMATCH:
    if (!filename) {
	logg("Filename cannot be NULL for MULTISCAN or CONTSCAN.\n");
	return -1;
    }
    len = strlen(filename) + strlen(scancmd[scantype]) + 3;
    if (!(bol = malloc(len))) {
	logg("!Cannot allocate a command buffer: %s\n", strerror(errno));
	return -1;
    }
    sprintf(bol, "z%s %s", scancmd[scantype], filename);
    if(sendln(sockd, bol, len)) {
	free(bol);
	return -1;
    }
    free(bol);
    break;

    case STREAM:
        /* NULL filename safe in send_stream() */
	len = send_stream(sockd, filename);
	break;
#ifdef HAVE_FD_PASSING
    case FILDES:
        /* NULL filename safe in send_fdpass() */
	len = send_fdpass(sockd, filename);
	break;
#endif
    }

    if(len <=0) {
	*printok = 0;
	if(errors)
	    (*errors)++;
	return len;
    }

    while((len = recvln(&rcv, &bol, &eol))) {
	if(len == -1) return -1;
	beenthere = 1;
	if(!filename) logg("~%s\n", bol);
	if(len > 7) {
	    char *colon = strrchr(bol, ':');
	    if(colon && colon[1] != ' ') {
		char *br;
		*colon = 0;
		br = strrchr(bol, '(');
		if(br)
		    *br = 0;
		colon = strrchr(bol, ':');
	    }
	    if(!colon) {
		char * unkco = "UNKNOWN COMMAND";
		if (!strncmp(bol, unkco, sizeof(unkco) - 1))
		    logg("clamd replied \"UNKNOWN COMMAND\". Command was %s\n", 
			 (scantype < 0 || scantype > MAX_SCANTYPE) ? "unidentified" :
			                                             scancmd[scantype]);
		else
		    logg("Failed to parse reply: \"%s\"\n", bol);
		return -1;
	    } else if(!memcmp(eol - 7, " FOUND", 6)) {
		*(eol - 7) = 0;
		*printok = 0;
		infected++;
		if(filename) {
		    if(scantype >= STREAM) {
			logg("~%s%s FOUND\n", filename, colon);
			if(action) action(filename);
		    } else {
			logg("~%s FOUND\n", bol);
			*colon = '\0';
			if(action)
			    action(bol);
		    }
		}
	    } else if(!memcmp(eol-7, " ERROR", 6)) {
		if(errors)
		    (*errors)++;
		*printok = 0;
		if(filename) {
		    if(scantype >= STREAM)
			logg("~%s%s\n", filename, colon);
		    else
			logg("~%s\n", bol);
		}
	    }
	}
    }
    if(!beenthere) {
        if (!filename) {
	    logg("STDIN: noreply from clamd\n.");
	    return -1;
	}
        if(CLAMSTAT(filename, &sb) == -1) {
	    logg("~%s: stat() failed with %s, clamd may not be responding\n",
		 filename, strerror(errno));
	    return -1;
	}
	if(!S_ISDIR(sb.st_mode)) {
	    logg("~%s: no reply from clamd\n", filename);
	    return -1;
	}
    }
    return infected;
}
Exemple #2
0
/* FTW callback for scanning in IDSESSION mode
 * Returns SUCCESS on success, CL_EXXX or BREAK on error */
static int parallel_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) {
    struct client_parallel_data *c = (struct client_parallel_data *)data->data;
    struct SCANID *cid;
    int res = CL_CLEAN;

    if(chkpath(path))
	return CL_SUCCESS;
    c->files++;
    switch(reason) {
    case error_stat:
	logg("!Can't access file %s\n", path);
	c->errors++;
	return CL_SUCCESS;
    case error_mem:
	logg("!Memory allocation failed in ftw\n");
	c->errors++;
	return CL_EMEM;
    case warning_skipped_dir:
	logg("^Directory recursion limit reached\n");
	return CL_SUCCESS;
    case warning_skipped_special:
	logg("^%s: Not supported file type\n", path);
	c->errors++;
    case warning_skipped_link:
    case visit_directory_toplev:
	return CL_SUCCESS;
    case visit_file:
	break;
    }

    while(1) {
	/* consume all the available input to let some of the clamd
	 * threads blocked on send() to be dead.
	 * by doing so we shouldn't deadlock on the next recv() */
	fd_set rfds, wfds;
	FD_ZERO(&rfds);
	FD_SET(c->sockd, &rfds);
	FD_ZERO(&wfds);
	FD_SET(c->sockd, &wfds);
	if(select(c->sockd + 1, &rfds, &wfds, NULL, NULL) < 0) {
	    if(errno == EINTR) continue;
	    free(filename);
	    logg("!select() failed during session: %s\n", strerror(errno));
	    return CL_BREAK;
	}
	if(FD_ISSET(c->sockd, &rfds)) {
	    if(dspresult(c)) {
		free(filename);
		return CL_BREAK;
	    } else continue;
	}
	if(FD_ISSET(c->sockd, &wfds)) break;
    }

    cid = (struct SCANID *)malloc(sizeof(struct SCANID));
    if(!cid) {
	free(filename);
	logg("!Failed to allocate scanid entry: %s\n", strerror(errno));
	return CL_BREAK;
    }
    cid->id = ++c->lastid;
    cid->file = filename;
    cid->next = c->ids;
    c->ids = cid;

    switch(c->scantype) {
#ifdef HAVE_FD_PASSING
    case FILDES:
	res = send_fdpass(c->sockd, filename);
	break;
#endif
    case STREAM:
	res = send_stream(c->sockd, filename);
	break;
    }
    if(res <= 0) {
	c->printok = 0;
	c->errors++;
	c->ids = cid->next;
	c->lastid--;
	free(cid);
	free(filename);
	return res ? CL_BREAK : CL_SUCCESS;
    }
    return CL_SUCCESS;
}
Exemple #3
0
/* Sends a proper scan request to clamd and parses its replies
 * This is used only in non IDSESSION mode
 * Returns the number of infected files or -1 on error */
int dsresult(int sockd, int scantype, const char *filename, int *printok) {
    int infected = 0, len, beenthere = 0;
    char *bol, *eol;
    struct RCVLN rcv;

    recvlninit(&rcv, sockd);

    switch(scantype) {
    case MULTI:
    case CONT:
        len = strlen(filename) + strlen(scancmd[scantype]) + 3;
        if (!(bol = malloc(len))) {
            logg("!Cannot allocate a command buffer: %s\n", strerror(errno));
            return -1;
        }
        sprintf(bol, "z%s %s", scancmd[scantype], filename);
        if(sendln(sockd, bol, len)) return -1;
        free(bol);
        break;

    case STREAM:
        len = send_stream(sockd, filename);
        break;
#ifdef HAVE_FD_PASSING
    case FILDES:
        len = send_fdpass(sockd, filename);
        break;
#endif
    }

    if(len <=0) {
        *printok = 0;
        return len;
    }

    while((len = recvln(&rcv, &bol, &eol))) {
        if(len == -1) return -1;
        beenthere = 1;
        if(!filename) logg("~%s\n", bol);
        if(len > 7) {
            char *colon = strrchr(bol, ':');
            if(!colon) {
                logg("Failed to parse reply\n");
                return -1;
            } else if(!memcmp(eol - 7, " FOUND", 6)) {
                *printok = 0;
                infected++;
                if(filename) {
                    if(scantype >= STREAM) {
                        logg("~%s%s\n", filename, colon);
                        if(action) action(filename);
                    } else {
                        logg("~%s\n", bol);
                        *colon = '\0';
                        if(action)
                            action(bol);
                    }
                }
            } else if(!memcmp(eol-7, " ERROR", 6)) {
                *printok = 0;
                if(filename) {
                    if(scantype >= STREAM)
                        logg("~%s%s\n", filename, colon);
                    else
                        logg("~%s\n", bol);
                }
            }
        }
    }
    if(!beenthere) {
        logg("~%s: no reply from clamd\n", filename ? filename : "STDIN");
        return -1;
    }
    return infected;
}