/* * zCOMMANDS are delimited by \0 * nCOMMANDS are delimited by \n * Old-style non-prefixed commands are one packet, optionally delimited by \n, * with trailing \r|\n ignored */ static const char *get_cmd(struct fd_buf *buf, size_t off, size_t *len, char *term, int *oldstyle) { char *pos; if (!buf->off || off >= buf->off) { *len = 0; return NULL; } *term = '\n'; switch (buf->buffer[off]) { /* commands terminated by delimiters */ case 'z': *term = '\0'; case 'n': pos = memchr(buf->buffer + off, *term, buf->off - off); if (!pos) { /* we don't have another full command yet */ *len = 0; return NULL; } *pos = '\0'; if (*term) { *len = cli_chomp(buf->buffer + off); } else { *len = pos - buf->buffer - off; } *oldstyle = 0; return buf->buffer + off + 1; default: /* one packet = one command */ if (off) return NULL; pos = memchr(buf->buffer, '\n', buf->off); if (pos) { *len = pos - buf->buffer; *pos = '\0'; } else { *len = buf->off; buf->buffer[buf->off] = '\0'; } cli_chomp(buf->buffer); *oldstyle = 1; return buf->buffer; } }
/* * Save the uuencoded part of the file as it is read in since there's no need * to include it in the parse tree. Saves memory and parse time. * Return < 0 for failure */ int uudecodeFile(message *m, const char *firstline, const char *dir, fmap_t *map, size_t *at) { fileblob *fb; char buffer[RFC2821LENGTH + 1]; char *filename = cli_strtok(firstline, 2, " "); if(filename == NULL) return -1; fb = fileblobCreate(); if(fb == NULL) { free(filename); return -1; } fileblobSetFilename(fb, dir, filename); cli_dbgmsg("uudecode %s\n", filename); free(filename); while(fmap_gets(map, buffer, at, sizeof(buffer) - 1)) { unsigned char data[1024]; const unsigned char *uptr; size_t len; cli_chomp(buffer); if(strcasecmp(buffer, "end") == 0) break; if(buffer[0] == '\0') break; uptr = decodeLine(m, UUENCODE, buffer, data, sizeof(data)); if(uptr == NULL) break; len = (size_t)(uptr - data); if((len > 62) || (len == 0)) break; if(fileblobAddData(fb, data, len) < 0) break; } fileblobDestroy(fb); return 1; }
int command(int desc, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt, int timeout) { char buff[1025]; int bread, opt, retval; struct cfgstruct *cpt; retval = poll_fd(desc, timeout); switch (retval) { case 0: /* timeout */ return -2; case -1: mdprintf(desc, "ERROR\n"); logg("!Command: poll_fd failed.\n"); return -1; } while((bread = readsock(desc, buff, 1024)) == -1 && errno == EINTR); if(bread == 0) { /* Connection closed */ return -1; } if(bread < 0) { logg("!Command parser: read() failed.\n"); /* at least try to display this error message */ /* mdprintf(desc, "ERROR: Command parser: read() failed.\n"); */ return -1; } buff[bread] = 0; cli_chomp(buff); if(!strncmp(buff, CMD1, strlen(CMD1))) { /* SCAN */ if(scan(buff + strlen(CMD1) + 1, NULL, root, limits, options, copt, desc, 0) == -2) if(cfgopt(copt, "ExitOnOOM")) return COMMAND_SHUTDOWN; } else if(!strncmp(buff, CMD2, strlen(CMD2))) { /* RAWSCAN */ opt = options & ~CL_SCAN_ARCHIVE; if(scan(buff + strlen(CMD2) + 1, NULL, root, NULL, opt, copt, desc, 0) == -2) if(cfgopt(copt, "ExitOnOOM")) return COMMAND_SHUTDOWN; } else if(!strncmp(buff, CMD3, strlen(CMD3))) { /* QUIT */ return COMMAND_SHUTDOWN; } else if(!strncmp(buff, CMD4, strlen(CMD4))) { /* RELOAD */ mdprintf(desc, "RELOADING\n"); return COMMAND_RELOAD; } else if(!strncmp(buff, CMD5, strlen(CMD5))) { /* PING */ mdprintf(desc, "PONG\n"); } else if(!strncmp(buff, CMD6, strlen(CMD6))) { /* CONTSCAN */ if(scan(buff + strlen(CMD6) + 1, NULL, root, limits, options, copt, desc, 1) == -2) if(cfgopt(copt, "ExitOnOOM")) return COMMAND_SHUTDOWN; } else if(!strncmp(buff, CMD7, strlen(CMD7))) { /* VERSION */ const char *dbdir; char *path; struct cl_cvd *daily; if((cpt = cfgopt(copt, "DatabaseDirectory")) || (cpt = cfgopt(copt, "DataDirectory"))) dbdir = cpt->strarg; else dbdir = cl_retdbdir(); if(!(path = mmalloc(strlen(dbdir) + 11))) { mdprintf(desc, "Memory allocation error - SHUTDOWN forced\n"); return COMMAND_SHUTDOWN; } sprintf(path, "%s/daily.cvd", dbdir); if((daily = cl_cvdhead(path))) { time_t t = (time_t) daily->stime; pthread_mutex_lock(&ctime_mutex); mdprintf(desc, "ClamAV "VERSION"/%d/%s", daily->version, ctime(&t)); pthread_mutex_unlock(&ctime_mutex); cl_cvdfree(daily); } else { mdprintf(desc, "ClamAV "VERSION"\n"); } free(path); } else if(!strncmp(buff, CMD8, strlen(CMD8))) { /* STREAM */ if(scanstream(desc, NULL, root, limits, options, copt) == CL_EMEM) if(cfgopt(copt, "ExitOnOOM")) return COMMAND_SHUTDOWN; } else if(!strncmp(buff, CMD9, strlen(CMD9))) { /* SESSION */ return COMMAND_SESSION; } else if(!strncmp(buff, CMD10, strlen(CMD10))) { /* END */ return COMMAND_END; } else if(!strncmp(buff, CMD11, strlen(CMD11))) { /* SHUTDOWN */ return COMMAND_SHUTDOWN; } else if(!strncmp(buff, CMD12, strlen(CMD12))) { /* FD */ int fd = atoi(buff + strlen(CMD12) + 1); scanfd(fd, NULL, root, limits, options, copt, desc, 0); close(fd); /* FIXME: should we close it here? */ } else { mdprintf(desc, "UNKNOWN COMMAND\n"); } return 0; /* no error and no 'special' command executed */ }
/* * legend: * ! - ERROR: * ^ - WARNING: * ~ - normal * # - normal, not foreground (logfile and syslog only) * * - verbose * $ - debug * none - normal * * Default Foreground LogVerbose Debug Syslog * ! yes mprintf yes yes LOG_ERR * ^ yes mprintf yes yes LOG_WARNING * ~ yes mprintf yes yes LOG_INFO * # yes no yes yes LOG_INFO * * no mprintf yes yes LOG_DEBUG * $ no mprintf no yes LOG_DEBUG * none yes mprintf yes yes LOG_INFO */ int logg(const char *str, ...) { va_list args; char buffer[1025], *abuffer = NULL, *buff; time_t currtime; size_t len; mode_t old_umask; #ifdef F_WRLCK struct flock fl; #endif if ((*str == '$' && logg_verbose < 2) || (*str == '*' && !logg_verbose)) return 0; ARGLEN(args, str, len); if(len <= sizeof(buffer)) { len = sizeof(buffer); buff = buffer; } else { abuffer = malloc(len); if(!abuffer) { len = sizeof(buffer); buff = buffer; } else { buff = abuffer; } } va_start(args, str); vsnprintf(buff, len, str, args); va_end(args); buff[len - 1] = 0; #ifdef CL_THREAD_SAFE pthread_mutex_lock(&logg_mutex); #endif logg_open(); if(!logg_fp && logg_file) { old_umask = umask(0037); if((logg_fp = fopen(logg_file, "at")) == NULL) { umask(old_umask); #ifdef CL_THREAD_SAFE pthread_mutex_unlock(&logg_mutex); #endif printf("ERROR: Can't open %s in append mode (check permissions!).\n", logg_file); if(len > sizeof(buffer)) free(abuffer); return -1; } else umask(old_umask); #ifdef F_WRLCK if(logg_lock) { memset(&fl, 0, sizeof(fl)); fl.l_type = F_WRLCK; if(fcntl(fileno(logg_fp), F_SETLK, &fl) == -1) { #ifdef EOPNOTSUPP if(errno == EOPNOTSUPP) printf("WARNING: File locking not supported (NFS?)\n"); else #endif { #ifdef CL_THREAD_SAFE pthread_mutex_unlock(&logg_mutex); #endif printf("ERROR: %s is locked by another process\n", logg_file); if(len > sizeof(buffer)) free(abuffer); return -1; } } } #endif } if(logg_fp) { char flush = !logg_noflush; /* Need to avoid logging time for verbose messages when logverbose is not set or we get a bunch of timestamps in the log without newlines... */ if(logg_time && ((*buff != '*') || logg_verbose)) { char timestr[32]; time(&currtime); cli_ctime(&currtime, timestr, sizeof(timestr)); /* cut trailing \n */ timestr[strlen(timestr)-1] = '\0'; fprintf(logg_fp, "%s -> ", timestr); } if(*buff == '!') { fprintf(logg_fp, "ERROR: %s", buff + 1); flush = 1; } else if(*buff == '^') { if(!logg_nowarn) fprintf(logg_fp, "WARNING: %s", buff + 1); flush = 1; } else if(*buff == '*' || *buff == '$') { fprintf(logg_fp, "%s", buff + 1); } else if(*buff == '#' || *buff == '~') { fprintf(logg_fp, "%s", buff + 1); } else fprintf(logg_fp, "%s", buff); if (flush) fflush(logg_fp); } if(logg_foreground) { if(buff[0] != '#') mprintf("%s", buff); } #if defined(USE_SYSLOG) && !defined(C_AIX) if(logg_syslog) { cli_chomp(buff); if(buff[0] == '!') { syslog(LOG_ERR, "%s", buff + 1); } else if(buff[0] == '^') { if(!logg_nowarn) syslog(LOG_WARNING, "%s", buff + 1); } else if(buff[0] == '*' || buff[0] == '$') { syslog(LOG_DEBUG, "%s", buff + 1); } else if(buff[0] == '#' || buff[0] == '~') { syslog(LOG_INFO, "%s", buff + 1); } else syslog(LOG_INFO, "%s", buff); } #endif #ifdef CL_THREAD_SAFE pthread_mutex_unlock(&logg_mutex); #endif if(len > sizeof(buffer)) free(abuffer); return 0; }