예제 #1
0
/*
 * 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;
    }
}
예제 #2
0
/*
 * 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;
}
예제 #3
0
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 */
}
예제 #4
0
/*
 * 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;
}