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; }
/* 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; }
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; }
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; }