int get_clamd_version(const struct optstruct *opts) { char *buff; int len, sockd; struct RCVLN rcv; isremote(opts); if((sockd = dconnect()) < 0) return 2; recvlninit(&rcv, sockd); if(sendln(sockd, "zVERSION", 9)) { closesocket(sockd); return 2; } while((len = recvln(&rcv, &buff, NULL))) { if(len == -1) { logg("!Error occoured while receiving version information.\n"); break; } printf("%s\n", buff); } closesocket(sockd); return 0; }
/* Sends a proper scan request to clamd and parses its replies * This is used only in IDSESSION mode * Returns 0 on success, 1 on hard failures, 2 on len == 0 (bb#1717) */ static int dspresult(struct client_parallel_data *c) { const char *filename; char *bol, *eol; unsigned int rid; int len; struct SCANID **id = NULL; struct RCVLN rcv; recvlninit(&rcv, c->sockd); do { len = recvln(&rcv, &bol, &eol); if(len < 0) return 1; if(!len) return 2; if((rid = atoi(bol))) { id = &c->ids; while(*id) { if((*id)->id == rid) break; id = &((*id)->next); } if(!*id) id = NULL; } if(!id) { logg("!Bogus session id from clamd\n"); return 1; } filename = (*id)->file; if(len > 7) { char *colon = strrchr(bol, ':'); if(!colon) { logg("!Failed to parse reply\n"); free((void *)filename); return 1; } else if(!memcmp(eol - 7, " FOUND", 6)) { c->infected++; c->printok = 0; logg("~%s%s\n", filename, colon); if(action) action(filename); } else if(!memcmp(eol-7, " ERROR", 6)) { c->errors++; c->printok = 0; logg("~%s%s\n", filename, colon); } } free((void *)filename); bol = (char *)*id; *id = (*id)->next; free(bol); } while(rcv.cur != rcv.buf); /* clamd sends whole lines, so, on partial lines, we just assume more data can be recv()'d with close to zero latency */ return 0; }
int reload_clamd_database(const struct optstruct *opts) { char *buff; int len, sockd; struct RCVLN rcv; isremote(opts); if((sockd = dconnect()) < 0) return 2; recvlninit(&rcv, sockd); if(sendln(sockd, "zRELOAD", 8)) { closesocket(sockd); return 2; } if(!(len = recvln(&rcv, &buff, NULL)) || len < 10 || memcmp(buff, "RELOADING", 9)) { logg("!Clamd did not reload the database\n"); closesocket(sockd); return 2; } closesocket(sockd); return 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; }
/* 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; }