예제 #1
0
파일: trace.c 프로젝트: tongfw/pcp
static int
_pmtraceremaperr(int sts)
{
    int save_oserror;
    int socket_closed;

    /*
     * sts is negative.
     * Use __pmSocketClosed() to decode it, since it may have come from
     * __pmSecureSocketsError(). __pmSocketClosed uses oserror() and expects it to
     * be non-negative.
     */
    save_oserror = oserror();
    setoserror(-sts);
    socket_closed = __pmSocketClosed();
    setoserror(save_oserror);

#ifdef PMTRACE_DEBUG
    if (__pmstate & PMTRACE_STATE_COMMS)
	fprintf(stderr, "_pmtraceremaperr: status %d remapped to %d\n", sts,
		socket_closed ? PMTRACE_ERR_IPC : sts);
#endif

    if (socket_closed) {
	_pmtimedout = 1;
	return PMTRACE_ERR_IPC;
    }
    return sts;
}
예제 #2
0
파일: pdu.c 프로젝트: rwongone/pcp
/* result is pinned on successful return */
int
__pmGetPDU(int fd, int mode, int timeout, __pmPDU **result)
{
    int			need;
    int			len;
    static int		maxsize = PDU_CHUNK;
    char		*handle;
    __pmPDU		*pdubuf;
    __pmPDU		*pdubuf_prev;
    __pmPDUHdr		*php;

    if ((pdubuf = __pmFindPDUBuf(maxsize)) == NULL)
	return -oserror();

    /* First read - try to read the header */
    len = pduread(fd, (void *)pdubuf, sizeof(__pmPDUHdr), HEADER, timeout);
    php = (__pmPDUHdr *)pdubuf;

    if (len < (int)sizeof(__pmPDUHdr)) {
	if (len == -1) {
	    if (__pmSocketClosed()) {
		len = 0;
	    } else {
		char	errmsg[PM_MAXERRMSGLEN];
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: len=%d: %s", fd, len, pmErrStr_r(-oserror(), errmsg, sizeof(errmsg)));
	    }
	}
	else if (len >= (int)sizeof(php->len)) {
	    /*
	     * Have part of a PDU header.  Enough for the "len"
	     * field to be valid, but not yet all of it - save
	     * what we have received and try to read some more.
	     * Note this can only happen once per PDU, so the
	     * ntohl() below will _only_ be done once per PDU.
	     */
	    goto check_read_len;	/* continue, do not return */
	}
	else if (len == PM_ERR_TIMEOUT) {
	    __pmUnpinPDUBuf(pdubuf);
	    return PM_ERR_TIMEOUT;
	}
	else if (len < 0) {
	    char	errmsg[PM_MAXERRMSGLEN];
	    __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: len=%d: %s", fd, len, pmErrStr_r(len, errmsg, sizeof(errmsg)));
	    __pmUnpinPDUBuf(pdubuf);
	    return PM_ERR_IPC;
	}
	else if (len > 0) {
	    __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: bad len=%d", fd, len);
	    __pmUnpinPDUBuf(pdubuf);
	    return PM_ERR_IPC;
	}

	/*
	 * end-of-file with no data
	 */
	__pmUnpinPDUBuf(pdubuf);
	return 0;
    }

check_read_len:
    php->len = ntohl(php->len);
    if (php->len < (int)sizeof(__pmPDUHdr)) {
	/*
	 * PDU length indicates insufficient bytes for a PDU header
	 * ... looks like DOS attack like PV 935490
	 */
	__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d illegal PDU len=%d in hdr", fd, php->len);
	__pmUnpinPDUBuf(pdubuf);
	return PM_ERR_IPC;
    }
    else if (mode == LIMIT_SIZE && php->len > ceiling) {
	/*
	 * Guard against denial of service attack ... don't accept PDUs
	 * from clients that are larger than 64 Kbytes (ceiling)
	 * (note, pmcd and pmdas have to be able to _send_ large PDUs,
	 * e.g. for a pmResult or instance domain enquiry)
	 */
	__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d bad PDU len=%d in hdr exceeds maximum client PDU size (%d)",
		      fd, php->len, ceiling);

	__pmUnpinPDUBuf(pdubuf);
	return PM_ERR_TOOBIG;
    }

    if (len < php->len) {
	/*
	 * need to read more ...
	 */
	int		tmpsize;
	int		have = len;

	PM_INIT_LOCKS();
	PM_LOCK(__pmLock_libpcp);
	if (php->len > maxsize) {
	    tmpsize = PDU_CHUNK * ( 1 + php->len / PDU_CHUNK);
	    maxsize = tmpsize;
	}
	else
	    tmpsize = maxsize;
	PM_UNLOCK(__pmLock_libpcp);

	pdubuf_prev = pdubuf;
	if ((pdubuf = __pmFindPDUBuf(tmpsize)) == NULL) {
	    __pmUnpinPDUBuf(pdubuf_prev);
	    return -oserror();
	}

	memmove((void *)pdubuf, (void *)php, len);
	__pmUnpinPDUBuf(pdubuf_prev);

	php = (__pmPDUHdr *)pdubuf;
	need = php->len - have;
	handle = (char *)pdubuf;
	/* block until all of the PDU is received this time */
	len = pduread(fd, (void *)&handle[len], need, BODY, timeout);
	if (len != need) {
	    if (len == PM_ERR_TIMEOUT) {
		__pmUnpinPDUBuf(pdubuf);
		return PM_ERR_TIMEOUT;
	    }
	    else if (len < 0) {
		char	errmsg[PM_MAXERRMSGLEN];
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d data read: len=%d: %s", fd, len, pmErrStr_r(-oserror(), errmsg, sizeof(errmsg)));
	    }
	    else
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d data read: have %d, want %d, got %d", fd, have, need, len);
	    /*
	     * only report header fields if you've read enough bytes
	     */
	    if (len > 0)
		have += len;
	    if (have >= (int)(sizeof(php->len)+sizeof(php->type)+sizeof(php->from)))
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: PDU hdr: len=0x%x type=0x%x from=0x%x", php->len, (unsigned)ntohl(php->type), (unsigned)ntohl(php->from));
	    else if (have >= (int)(sizeof(php->len)+sizeof(php->type)))
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: PDU hdr: len=0x%x type=0x%x", php->len, (unsigned)ntohl(php->type));
	    __pmUnpinPDUBuf(pdubuf);
	    return PM_ERR_IPC;
	}
    }

    *result = (__pmPDU *)php;
    php->type = ntohl((unsigned int)php->type);
    if (php->type < 0) {
	/*
	 * PDU type is bad ... could be a possible mem leak attack like
	 * https://bugzilla.redhat.com/show_bug.cgi?id=841319
	 */
	__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d illegal PDU type=%d in hdr", fd, php->type);
	__pmUnpinPDUBuf(pdubuf);
	return PM_ERR_IPC;
    }
    php->from = ntohl((unsigned int)php->from);
#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_PDU) {
	int	j;
	char	*p;
	int	jend = PM_PDU_SIZE(php->len);
	char	strbuf[20];

        /* clear the padding bytes, lest they contain garbage */
	p = (char *)*result + php->len;
	while (p < (char *)*result + jend*sizeof(__pmPDU))
	    *p++ = '~';	/* buffer end */

	if (mypid == -1)
	    mypid = (int)getpid();
	fprintf(stderr, "[%d]pmGetPDU: %s fd=%d len=%d from=%d",
		mypid, __pmPDUTypeStr_r(php->type, strbuf, sizeof(strbuf)), fd, php->len, php->from);
	for (j = 0; j < jend; j++) {
	    if ((j % 8) == 0)
		fprintf(stderr, "\n%03d: ", j);
	    fprintf(stderr, "%8x ", (*result)[j]);
	}
	putc('\n', stderr);
    }
#endif
    if (php->type >= PDU_START && php->type <= PDU_FINISH)
	__pmPDUCntIn[php->type-PDU_START]++;

    /*
     * Note php points into the PDU buffer pdubuf that remains pinned
     * and php is returned via the result parameter ... see the
     * thread-safe comments above
     */
    return php->type;
}
예제 #3
0
파일: pdu.c 프로젝트: rwongone/pcp
int
__pmXmitPDU(int fd, __pmPDU *pdubuf)
{
    int		socketipc = __pmSocketIPC(fd);
    int		off = 0;
    int		len;
    __pmPDUHdr	*php = (__pmPDUHdr *)pdubuf;

    __pmIgnoreSignalPIPE();

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_PDU) {
	int	j;
	char	*p;
	int	jend = PM_PDU_SIZE(php->len);
	char	strbuf[20];

        /* clear the padding bytes, lest they contain garbage */
	p = (char *)pdubuf + php->len;
	while (p < (char *)pdubuf + jend*sizeof(__pmPDU))
	    *p++ = '~';	/* buffer end */

	if (mypid == -1)
	    mypid = (int)getpid();
	fprintf(stderr, "[%d]pmXmitPDU: %s fd=%d len=%d",
		mypid, __pmPDUTypeStr_r(php->type, strbuf, sizeof(strbuf)), fd, php->len);
	for (j = 0; j < jend; j++) {
	    if ((j % 8) == 0)
		fprintf(stderr, "\n%03d: ", j);
	    fprintf(stderr, "%8x ", pdubuf[j]);
	}
	putc('\n', stderr);
    }
#endif
    len = php->len;

    php->len = htonl(php->len);
    php->from = htonl(php->from);
    php->type = htonl(php->type);
    while (off < len) {
	char *p = (char *)pdubuf;
	int n;

	p += off;

	n = socketipc ? __pmSend(fd, p, len-off, 0) : write(fd, p, len-off);
	if (n < 0)
	    break;
	off += n;
    }
    php->len = ntohl(php->len);
    php->from = ntohl(php->from);
    php->type = ntohl(php->type);

    if (off != len) {
	if (socketipc) {
	    if (__pmSocketClosed())
		return PM_ERR_IPC;
	    return neterror() ? -neterror() : PM_ERR_IPC;
	}
	return oserror() ? -oserror() : PM_ERR_IPC;
    }

    __pmOverrideLastFd(fd);
    if (php->type >= PDU_START && php->type <= PDU_FINISH)
	__pmPDUCntOut[php->type-PDU_START]++;

    return off;
}
예제 #4
0
파일: http_client.c 프로젝트: ubccr/pcp
static int
http_client_get(http_client *cp)
{
    char		buf[BUFSIZ];
    char		host[MAXHOSTNAMELEN];
    char		*bp = &buf[0], *url = cp->url;
    http_parser_url	*up = &cp->parser_url;
    const char		*path, *agent, *version, *protocol;
    size_t		hostlen, len = 0, length;
    int			sts;


    /* sanitize request parameters */
    if ((agent = cp->user_agent) == NULL)
	agent = pmProgname;
    if ((version = cp->agent_vers) == NULL)
	version = "1.0";
    if ((path = url + up->field_data[UF_PATH].off) == NULL ||
	up->field_data[UF_PATH].off == 0 ||
	strchr(path, '/') == NULL){
	path = "/";	/* assume root-level request */
    }
    hostlen = up->field_data[UF_HOST].len;
    strncpy(host, url + up->field_data[UF_HOST].off, hostlen);
    host[hostlen] = '\0';
    //    strncpy(host, "localhost", sizeof("localhost"));
    //    host[sizeof("localhost")] = '\0';
    //    strncpy(path, "/containers/8d70f8a47a6b6e515fb8e40d31da7928de70e883c235ba16b132e6a3b4f8267d/json", sizeof("/containers/8d70f8a47a6b6e515fb8e40d31da7928de70e883c235ba16b132e6a3b4f8267d/json"));
    //    __pmNotifyErr(LOG_DEBUG, "hit here: %s", cp->type_buffer);
    
    protocol = url + up->field_data[UF_SCHEMA].off;
    length = up->field_data[UF_SCHEMA].len;
    /* prepare and send a GET request */
    if (length == sizeof(HTTP)-1 && strncmp(protocol, UNIX, length) == 0) {
	len += snprintf(bp+len, sizeof(buf)-len, "GET %s HTTP/%s\r\n",
			cp->type_buffer, http_versionstr(cp->http_version));
	len += snprintf(bp+len, sizeof(buf)-len, "Host: %s\r\n", "localhost");
    }
    else
    {
	len += snprintf(bp+len, sizeof(buf)-len, "GET %s HTTP/%s\r\n",
			path, http_versionstr(cp->http_version));
	len += snprintf(bp+len, sizeof(buf)-len, "Host: %s\r\n", host);
    }
    len += snprintf(bp+len, sizeof(buf)-len, "User-Agent: %s/%s\r\n",
			agent, version);
    /* establish persistent connections (default in HTTP/1.1 onward) */
    if (cp->http_version < PV_HTTP_1_1)
	len += snprintf(bp+len, sizeof(buf)-len, "Connection: keep-alive\r\n");
    len += snprintf(bp+len, sizeof(buf)-len, "\r\n");
    buf[BUFSIZ-1] = '\0';

    if ((pmDebug & DBG_TRACE_HTTP) && (pmDebug & DBG_TRACE_DESPERATE))
	fprintf(stderr, "Sending HTTP request:\n\n%s\n", buf);

    if ((sts = __pmSend(cp->fd, buf, len, 0)) < 0) {
	if (__pmSocketClosed()) {
	    sts = 1;
	} else {
	    cp->error_code = sts;
	    sts = -1;
	}
	http_client_disconnect(cp);
    } else {
	sts = 0;
    }

    if (pmDebug & DBG_TRACE_HTTP)
	fprintf(stderr, "http_client_get sts=%d\n", sts);

    return sts;
}