int __pmSendLabelReq(int fd, int from, int ident, int type) { label_req_t *pp; int sts; int nid; if (type & PM_LABEL_CONTEXT) nid = htonl(PM_ID_NULL); else if (type & PM_LABEL_DOMAIN) nid = htonl(ident); else if (type & PM_LABEL_INDOM) nid = __htonpmInDom((pmInDom)ident); else if (type & (PM_LABEL_CLUSTER|PM_LABEL_ITEM|PM_LABEL_INSTANCES)) nid = __htonpmID((pmID)ident); else return -EINVAL; if ((pp = (label_req_t *)__pmFindPDUBuf(sizeof(label_req_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(label_req_t); pp->hdr.type = PDU_LABEL_REQ; pp->hdr.from = from; pp->ident = nid; pp->type = htonl(type); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
int __pmSendCreds(int fd, int from, int credcount, const __pmCred *credlist) { size_t need; creds_t *pp; int i; int sts; if (credcount <= 0 || credcount > LIMIT_CREDS || credlist == NULL) return PM_ERR_IPC; need = sizeof(creds_t) + ((credcount-1) * sizeof(__pmCred)); if ((pp = (creds_t *)__pmFindPDUBuf((int)need)) == NULL) return -oserror(); pp->hdr.len = (int)need; pp->hdr.type = PDU_CREDS; pp->hdr.from = from; pp->numcreds = htonl(credcount); if (pmDebugOptions.context) for (i = 0; i < credcount; i++) fprintf(stderr, "__pmSendCreds: #%d = %x\n", i, *(unsigned int*)&(credlist[i])); /* swab and fix bitfield order */ for (i = 0; i < credcount; i++) pp->credlist[i] = __htonpmCred(credlist[i]); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
int __pmSendInstanceReq(int fd, int from, const __pmTimeval *when, pmInDom indom, int inst, const char *name) { instance_req_t *pp; int need; int sts; need = sizeof(instance_req_t) - sizeof(int); if (name != NULL) need += PM_PDU_SIZE_BYTES(strlen(name)); if ((pp = (instance_req_t *)__pmFindPDUBuf(need)) == NULL) return -oserror(); pp->hdr.len = need; pp->hdr.type = PDU_INSTANCE_REQ; pp->hdr.from = from; pp->when.tv_sec = htonl((__int32_t)when->tv_sec); pp->when.tv_usec = htonl((__int32_t)when->tv_usec); pp->indom = __htonpmInDom(indom); pp->inst = htonl(inst); if (name == NULL) pp->namelen = 0; else { pp->namelen = (int)strlen(name); memcpy((void *)pp->name, (void *)name, pp->namelen); if ((pp->namelen % sizeof(__pmPDU)) != 0) { /* clear the padding bytes, lest they contain garbage */ int pad; char *padp = pp->name + pp->namelen; for (pad = sizeof(__pmPDU) - 1; pad >= (pp->namelen % sizeof(__pmPDU)); pad--) *padp++ = '~'; /* buffer end */ } pp->namelen = htonl(pp->namelen); } sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
int __pmSendDesc(int fd, int ctx, pmDesc *desc) { desc_t *pp; int sts; if ((pp = (desc_t *)__pmFindPDUBuf(sizeof(desc_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(desc_t); pp->hdr.type = PDU_DESC; pp->hdr.from = ctx; pp->desc.type = htonl(desc->type); pp->desc.sem = htonl(desc->sem); pp->desc.indom = __htonpmInDom(desc->indom); pp->desc.units = __htonpmUnits(desc->units); pp->desc.pmid = __htonpmID(desc->pmid); sts =__pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
int __pmSendAttr(int fd, int from, int attr, const char *value, int length) { size_t need; attr_t *pp; int i; int sts; if (length < 0 || length >= LIMIT_ATTR_PDU) return PM_ERR_IPC; need = (sizeof(*pp) - sizeof(pp->value)) + length; if ((pp = (attr_t *)__pmFindPDUBuf((int)need)) == NULL) return -oserror(); pp->hdr.len = (int)need; pp->hdr.type = PDU_ATTR; pp->hdr.from = from; pp->attr = htonl(attr); memcpy(&pp->value, value, length); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_ATTR) { char buffer[LIMIT_ATTR_PDU]; for (i = 0; i < length; i++) buffer[i] = isprint((int)value[i]) ? value[i] : '.'; buffer[length] = buffer[LIMIT_ATTR_PDU-1] = '\0'; if (attr) fprintf(stderr, "__pmSendAttr [len=%d]: attr=0x%x value=\"%s\"\n", length, attr, buffer); else fprintf(stderr, "__pmSendAttr [len=%d]: payload=\"%s\"\n", length, buffer); } #endif sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
int __pmSendText(int fd, int ctx, int ident, const char *buffer) { text_t *pp; size_t need; size_t len = strlen(buffer); int sts; need = sizeof(text_t) - sizeof(pp->buffer) + PM_PDU_SIZE_BYTES(len); if ((pp = (text_t *)__pmFindPDUBuf((int)need)) == NULL) return -oserror(); pp->hdr.len = (int)need; pp->hdr.type = PDU_TEXT; pp->hdr.from = ctx; /* * Note: ident argument must already be in network byte order. * The caller has to do this because the type of ident is not * part of the transmitted PDU_TEXT pdu; ident may be either * a pmID or pmInDom, and so the caller must use either * __htonpmID or __htonpmInDom (respectively). */ pp->ident = ident; pp->buflen = htonl(len); memcpy((void *)pp->buffer, (void *)buffer, len); if (len % sizeof(__pmPDU) != 0) { /* clear the padding bytes, lest they contain garbage */ int pad; char *padp = pp->buffer + len; for (pad = sizeof(__pmPDU) - 1; pad >= (len % sizeof(__pmPDU)); pad--) *padp++ = '~'; /* buffer end */ } sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
int __pmSendTextReq(int fd, int from, int ident, int type) { text_req_t *pp; int sts; if ((pp = (text_req_t *)__pmFindPDUBuf(sizeof(text_req_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(text_req_t); pp->hdr.type = PDU_TEXT_REQ; pp->hdr.from = from; if (type & PM_TEXT_PMID) pp->ident = __htonpmID((pmID)ident); else /* (type & PM_TEXT_INDOM) */ pp->ident = __htonpmInDom((pmInDom)ident); type &= ~PM_TEXT_DIRECT; pp->type = htonl(type); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
int __pmSendDescReq(int fd, int from, pmID pmid) { desc_req_t *pp; int sts; if ((pp = (desc_req_t *)__pmFindPDUBuf(sizeof(desc_req_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(desc_req_t); pp->hdr.type = PDU_DESC_REQ; pp->hdr.from = from; pp->pmid = __htonpmID(pmid); #ifdef DESPERATE { char strbuf[20]; fprintf(stderr, "__pmSendDescReq: converted 0x%08x (%s) to 0x%08x\n", pmid, pmIDStr_r(pmid, strbuf, sizeof(strbuf)), pp->pmid); } #endif sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); 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 __pmSendLabel(int fd, int from, int ident, int type, pmLabelSet *sets, int nsets) { size_t labels_offset; size_t labels_need; size_t json_offset; size_t json_need; labelset_t *lsp; labels_t *pp; pmLabel *lp; int sts; int i, j; if (nsets < 0) return -EINVAL; labels_need = sizeof(labels_t) + (sizeof(labelset_t) * (nsets - 1)); json_need = 0; for (i = 0; i < nsets; i++) { json_need += sets[i].jsonlen; if (sets[i].nlabels > 0) labels_need += sets[i].nlabels * sizeof(pmLabel); } if ((pp = (labels_t *)__pmFindPDUBuf((int)labels_need + json_need)) == NULL) return -oserror(); pp->hdr.len = (int)(labels_need + json_need); pp->hdr.type = PDU_LABEL; pp->hdr.from = from; if (type & PM_LABEL_DOMAIN) pp->ident = htonl(ident); else if (type & (PM_LABEL_CLUSTER | PM_LABEL_ITEM | PM_LABEL_INSTANCES)) pp->ident = __htonpmID((pmID)ident); else if (type & PM_LABEL_INDOM) pp->ident = __htonpmInDom((pmInDom)ident); else pp->ident = htonl(PM_ID_NULL); pp->type = htonl(type); pp->padding = 0; pp->nsets = htonl(nsets); labels_offset = (char *)&pp->sets[0] - (char *)pp; json_offset = labels_need; /* JSONB immediately follows labelsets */ for (i = 0; i < nsets; i++) { lsp = (labelset_t *)((char *)pp + labels_offset); lsp->inst = htonl(sets[i].inst); lsp->nlabels = htonl(sets[i].nlabels); lsp->json = htonl(json_offset); lsp->jsonlen = htonl(sets[i].jsonlen); if (sets[i].nlabels > 0) { for (j = 0; j < sets[i].nlabels; j++) { lp = &lsp->labels[j]; lp->name = htons(sets[i].labels[j].name); lp->namelen = sets[i].labels[j].namelen; /* byte copy */ lp->flags = sets[i].labels[j].flags; /* byte copy */ lp->value = htons(sets[i].labels[j].value); lp->valuelen = htons(sets[i].labels[j].valuelen); } labels_offset += sets[i].nlabels * sizeof(pmLabel); } labels_offset += sizeof(labelset_t); if (sets[i].jsonlen) { memcpy((char *)pp + json_offset, sets[i].json, sets[i].jsonlen); json_offset += sets[i].jsonlen; } } if (pmDebugOptions.labels) DumpLabelSets("__pmSendLabel", ident, type, sets, nsets); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
int __pmSendProfile(int fd, int from, int ctxnum, __pmProfile *instprof) { __pmInDomProfile *prof, *p_end; profile_t *pduProfile; instprof_t *pduInstProf; __pmPDU *p; size_t need; __pmPDU *pdubuf; int sts; /* work out how much space we need and then alloc a pdu buf */ need = sizeof(profile_t) + instprof->profile_len * sizeof(instprof_t); for (prof = instprof->profile, p_end = prof + instprof->profile_len; prof < p_end; prof++) need += prof->instances_len * sizeof(int); if ((pdubuf = __pmFindPDUBuf((int)need)) == NULL) return -oserror(); p = (__pmPDU *)pdubuf; /* First the profile itself */ pduProfile = (profile_t *)p; pduProfile->hdr.len = (int)need; pduProfile->hdr.type = PDU_PROFILE; /* * note: context id may be sent twice due to protocol evolution and * backwards compatibility issues */ pduProfile->hdr.from = from; pduProfile->ctxnum = htonl(ctxnum); pduProfile->g_state = htonl(instprof->state); pduProfile->numprof = htonl(instprof->profile_len); pduProfile->pad = 0; p += sizeof(profile_t) / sizeof(__pmPDU); if (instprof->profile_len) { /* Next all the profile entries (if any) in one block */ for (prof = instprof->profile, p_end = prof + instprof->profile_len; prof < p_end; prof++) { pduInstProf = (instprof_t *)p; pduInstProf->indom = __htonpmInDom(prof->indom); pduInstProf->state = htonl(prof->state); pduInstProf->numinst = htonl(prof->instances_len); pduInstProf->pad = 0; p += sizeof(instprof_t) / sizeof(__pmPDU); } /* and then all the instances */ for (prof = instprof->profile, p_end = prof+instprof->profile_len; prof < p_end; prof++) { int j; /* and then the instances themselves (if any) */ for (j = 0; j < prof->instances_len; j++, p++) *p = htonl(prof->instances[j]); } } sts = __pmXmitPDU(fd, pdubuf); __pmUnpinPDUBuf(pdubuf); return sts; }
int __pmSendInstance(int fd, int from, __pmInResult *result) { instance_t *rp; instlist_t *ip; int need; int i; int j; int sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INDOM) __pmDumpInResult(stderr, result); #endif need = sizeof(*rp) - sizeof(rp->rest); /* instlist_t + name rounded up to a __pmPDU boundary */ for (i = 0; i < result->numinst; i++) { need += sizeof(*ip) - sizeof(ip->name); if (result->namelist != NULL) need += PM_PDU_SIZE_BYTES(strlen(result->namelist[i])); } if ((rp = (instance_t *)__pmFindPDUBuf(need)) == NULL) return -oserror(); rp->hdr.len = need; rp->hdr.type = PDU_INSTANCE; rp->hdr.from = from; rp->indom = __htonpmInDom(result->indom); rp->numinst = htonl(result->numinst); for (i = j = 0; i < result->numinst; i++) { ip = (instlist_t *)&rp->rest[j/sizeof(__pmPDU)]; if (result->instlist != NULL) ip->inst = htonl(result->instlist[i]); else /* weird, but this is going to be ignored at the other end */ ip->inst = htonl(PM_IN_NULL); if (result->namelist != NULL) { ip->namelen = (int)strlen(result->namelist[i]); memcpy((void *)ip->name, (void *)result->namelist[i], ip->namelen); if ((ip->namelen % sizeof(__pmPDU)) != 0) { /* clear the padding bytes, lest they contain garbage */ int pad; char *padp = ip->name + ip->namelen; for (pad = sizeof(__pmPDU) - 1; pad >= (ip->namelen % sizeof(__pmPDU)); pad--) *padp++ = '~'; /* buffer end */ } j += sizeof(*ip) - sizeof(ip->name) + PM_PDU_SIZE_BYTES(ip->namelen); ip->namelen = htonl(ip->namelen); } else { ip->namelen = 0; j += sizeof(*ip) - sizeof(ip->name); } } sts = __pmXmitPDU(fd, (__pmPDU *)rp); __pmUnpinPDUBuf(rp); return sts; }