/* FTW callback for scanning in non IDSESSION mode * Returns SUCCESS or BREAK on success, CL_EXXX on error */ static int serial_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) { struct client_serial_data *c = (struct client_serial_data *)data->data; int sockd, ret; const char *f = filename; UNUSEDPARAM(sb); 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"); case warning_skipped_link: return CL_SUCCESS; case warning_skipped_special: logg("^%s: Not supported file type\n", path); c->errors++; return CL_SUCCESS; case visit_directory_toplev: if(c->scantype >= STREAM) return CL_SUCCESS; f = path; filename = NULL; case visit_file: break; } if((sockd = dconnect()) < 0) { if(filename) free(filename); c->errors++; return CL_EOPEN; } ret = dsresult(sockd, c->scantype, f, &c->printok, &c->errors); if(filename) free(filename); closesocket(sockd); if(ret < 0) { c->errors++; return CL_EOPEN; } c->infected += ret; if(reason == visit_directory_toplev) return CL_BREAK; return CL_SUCCESS; }
/* Submitted by Richard Lyons <frob-clamav*webcentral.com.au> */ int dsfd(int sockfd, int fd, const struct optstruct *opt) { struct iovec iov[1]; struct msghdr msg; #ifdef HAVE_CONTROL_IN_MSGHDR #ifndef CMSG_SPACE #define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len)) #endif #ifndef CMSG_LEN #define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) #endif struct cmsghdr *cmsg; char tmp[CMSG_SPACE(sizeof(fd))]; #endif iov[0].iov_base = ""; iov[0].iov_len = 1; memset(&msg, 0, sizeof(msg)); msg.msg_iov = iov; msg.msg_iovlen = 1; #ifdef HAVE_CONTROL_IN_MSGHDR msg.msg_control = tmp; msg.msg_controllen = sizeof(tmp); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); *(int *)CMSG_DATA(cmsg) = fd; #endif #ifdef HAVE_ACCRIGHTS_IN_MSGHDR msg.msg_accrights = (caddr_t)&fd; msg.msg_accrightslen = sizeof(fd); #endif if (sendmsg(sockfd, &msg, 0) != iov[0].iov_len) { mprintf("@Can't write to the socket.\n"); return -1; } return dsresult(sockfd, opt); }
int client(const struct optstruct *opts, int *infected, int *err) { int remote, scantype, session = 0, errors = 0, scandash = 0, maxrec, flags = 0; const char *fname; scandash = (opts->filename && opts->filename[0] && !strcmp(opts->filename[0], "-") && !optget(opts, "file-list")->enabled && !opts->filename[1]); remote = isremote(opts) | optget(opts, "stream")->enabled; #ifdef HAVE_FD_PASSING if(!remote && optget(clamdopts, "LocalSocket")->enabled && (optget(opts, "fdpass")->enabled || scandash)) { scantype = FILDES; session = optget(opts, "multiscan")->enabled; } else #endif if(remote || scandash) { scantype = STREAM; session = optget(opts, "multiscan")->enabled; } else if(optget(opts, "multiscan")->enabled) scantype = MULTI; else if(optget(opts, "allmatch")->enabled) scantype = ALLMATCH; else scantype = CONT; maxrec = optget(clamdopts, "MaxDirectoryRecursion")->numarg; maxstream = optget(clamdopts, "StreamMaxLength")->numarg; if (optget(clamdopts, "FollowDirectorySymlinks")->enabled) flags |= CLI_FTW_FOLLOW_DIR_SYMLINK; if (optget(clamdopts, "FollowFileSymlinks")->enabled) flags |= CLI_FTW_FOLLOW_FILE_SYMLINK; flags |= CLI_FTW_TRIM_SLASHES; *infected = 0; if(scandash) { int sockd, ret; STATBUF sb; if(FSTAT(0, &sb) < 0) { logg("client.c: fstat failed for file name \"%s\", with %s\n.", opts->filename[0], strerror(errno)); return 2; } if((sb.st_mode & S_IFMT) != S_IFREG) scantype = STREAM; if((sockd = dconnect()) >= 0 && (ret = dsresult(sockd, scantype, NULL, &ret, NULL)) >= 0) *infected = ret; else errors = 1; if(sockd >= 0) closesocket(sockd); } else if(opts->filename || optget(opts, "file-list")->enabled) { if(opts->filename && optget(opts, "file-list")->enabled) logg("^Only scanning files from --file-list (files passed at cmdline are ignored)\n"); while((fname = filelist(opts, NULL))) { if(!strcmp(fname, "-")) { logg("!Scanning from standard input requires \"-\" to be the only file argument\n"); continue; } errors += client_scan(fname, scantype, infected, err, maxrec, session, flags); /* this may be too strict if(errors >= 10) { logg("!Too many errors\n"); break; } */ } } else { errors = client_scan("", scantype, infected, err, maxrec, session, flags); } return *infected ? 1 : (errors ? 2 : 0); }
int dsresult(int sockd, const struct optstruct *opt) { int infected = 0, waserror = 0; char buff[4096], *pt; FILE *fd; #ifndef C_OS2 if((fd = fdopen(dup(sockd), "r")) == NULL) { #else /* FIXME: accoriding to YD OS/2 does not support dup() for sockets */ if((fd = fdopen(sockd, "r")) == NULL) { #endif mprintf("@Can't open descriptor for reading.\n"); return -1; } while(fgets(buff, sizeof(buff), fd)) { if(strstr(buff, "FOUND\n")) { infected++; logg("%s", buff); mprintf("%s", buff); if(optl(opt, "move")) { /* filename: Virus FOUND */ if((pt = strrchr(buff, ':'))) { *pt = 0; move_infected(buff, opt); } else { mprintf("@Broken data format. File not moved.\n"); } } else if(optl(opt, "remove")) { if(!(pt = strrchr(buff, ':'))) { mprintf("@Broken data format. File not removed.\n"); } else { *pt = 0; if(unlink(buff)) { mprintf("%s: Can't remove.\n", buff); logg("%s: Can't remove.\n", buff); notremoved++; } else { mprintf("%s: Removed.\n", buff); logg("%s: Removed.\n", buff); } } } } if(strstr(buff, "ERROR\n")) { logg("%s", buff); mprintf("%s", buff); waserror = 1; } } #ifndef C_OS2 /* Small memory leak under OS/2 (see above) */ fclose(fd); #endif return infected ? infected : (waserror ? -1 : 0); } int dsfile(int sockd, const char *filename, const struct optstruct *opt) { int ret; char *scancmd; scancmd = mcalloc(strlen(filename) + 20, sizeof(char)); sprintf(scancmd, "CONTSCAN %s", filename); if(write(sockd, scancmd, strlen(scancmd)) <= 0) { mprintf("@Can't write to the socket.\n"); free(scancmd); return -1; } free(scancmd); ret = dsresult(sockd, opt); if(!ret) mprintf("%s: OK\n", filename); return ret; }