static int do_creds(__pmPDU *pb) { int i; int sts; int version = UNKNOWN_VERSION; int credcount; int sender; __pmCred *credlist = NULL; if ((sts = __pmDecodeCreds(pb, &sender, &credcount, &credlist)) < 0) { __pmNotifyErr(LOG_ERR, "do_creds: error decoding PDU: %s\n", pmErrStr(sts)); return PM_ERR_IPC; } for (i = 0; i < credcount; i++) { if (credlist[i].c_type == CVERSION) { version = credlist[i].c_vala; if ((sts = __pmSetVersionIPC(clientfd, version)) < 0) { free(credlist); return sts; } } } if (credlist) free(credlist); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) fprintf(stderr, "do_creds: pmlc version=%d\n", version); #endif return sts; }
/* Establish a new socket connection to a client */ ClientInfo * AcceptNewClient(int reqfd) { static unsigned int seq = 0; int i, fd; __pmSockLen addrlen; struct timeval now; i = NewClient(); addrlen = __pmSockAddrSize(); fd = __pmAccept(reqfd, client[i].addr, &addrlen); if (fd == -1) { if (neterror() == EPERM) { __pmNotifyErr(LOG_NOTICE, "AcceptNewClient(%d): " "Permission Denied\n", reqfd); client[i].fd = -1; DeleteClient(&client[i]); return NULL; } else { __pmNotifyErr(LOG_ERR, "AcceptNewClient(%d) __pmAccept: %s\n", reqfd, netstrerror()); Shutdown(); exit(1); } } if (fd > maxClientFd) maxClientFd = fd; pmcd_openfds_sethi(fd); __pmFD_SET(fd, &clientFds); __pmSetVersionIPC(fd, UNKNOWN_VERSION); /* before negotiation */ __pmSetSocketIPC(fd); client[i].fd = fd; client[i].status.connected = 1; client[i].status.changes = 0; memset(&client[i].attrs, 0, sizeof(__pmHashCtl)); /* * Note seq needs to be unique, but we're using a free running counter * and not bothering to check here ... unless we churn through * 4,294,967,296 (2^32) clients while one client remains connected * we won't have a problem */ client[i].seq = seq++; __pmtimevalNow(&now); client[i].start = now.tv_sec; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "AcceptNewClient(%d): client[%d] (fd %d)\n", reqfd, i, fd); #endif pmcd_trace(TR_ADD_CLIENT, i, 0, 0); return &client[i]; }
/* * client connects to pmcd handshake */ static int __pmConnectHandshake(int fd, const char *hostname, int ctxflags, __pmHashCtl *attrs) { __pmPDU *pb; int ok; int version; int challenge; int sts; int pinpdu; /* Expect an error PDU back from PMCD: ACK/NACK for connection */ pinpdu = sts = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); if (sts == PDU_ERROR) { /* * See comments in pmcd ... we actually get an extended error PDU * from pmcd, of the form * * :----------:-----------: * | status | challenge | * :----------:-----------: * * For a good connection, status is 0, else a PCP error code; * challenge contains server-side info (e.g. enabled features) */ version = __pmDecodeXtendError(pb, &sts, &challenge); if (version < 0) { __pmUnpinPDUBuf(pb); return version; } if (sts < 0) { __pmUnpinPDUBuf(pb); return sts; } if (version == PDU_VERSION2) { __pmPDUInfo pduinfo; __pmVersionCred handshake; int pduflags = 0; pduinfo = __ntohpmPDUInfo(*(__pmPDUInfo *)&challenge); if (pduinfo.features & PDU_FLAG_CREDS_REQD) /* * This is a mandatory connection feature - pmcd must be * sent user credential information one way or another - * i.e. via SASL2 authentication, or AF_UNIX peer creds. */ pduflags |= PDU_FLAG_CREDS_REQD; if (ctxflags) { /* * If an optional connection feature (e.g. encryption) is * desired, the pmcd that we're talking to must advertise * support for the feature. And if it did, the client in * turn must request it be enabled (now, via pduflags). */ if (ctxflags & (PM_CTXFLAG_SECURE|PM_CTXFLAG_RELAXED)) { if (pduinfo.features & PDU_FLAG_SECURE) { pduflags |= PDU_FLAG_SECURE; /* * Determine whether the server can send an ACK for a * secure connection request. We can still connect * whether it does or not, but we need to know the * protocol. */ if (pduinfo.features & PDU_FLAG_SECURE_ACK) pduflags |= PDU_FLAG_SECURE_ACK; } else if (ctxflags & PM_CTXFLAG_SECURE) { __pmUnpinPDUBuf(pb); return -EOPNOTSUPP; } } if (ctxflags & PM_CTXFLAG_COMPRESS) { if (pduinfo.features & PDU_FLAG_COMPRESS) pduflags |= PDU_FLAG_COMPRESS; else { __pmUnpinPDUBuf(pb); return -EOPNOTSUPP; } } if (ctxflags & PM_CTXFLAG_AUTH) { if (pduinfo.features & PDU_FLAG_AUTH) pduflags |= PDU_FLAG_AUTH; else { __pmUnpinPDUBuf(pb); return -EOPNOTSUPP; } } } /* * Negotiate connection version and features (via creds PDU) */ if ((ok = __pmSetVersionIPC(fd, version)) < 0) { __pmUnpinPDUBuf(pb); return ok; } memset(&handshake, 0, sizeof(handshake)); handshake.c_type = CVERSION; handshake.c_version = PDU_VERSION; handshake.c_flags = pduflags; sts = __pmSendCreds(fd, (int)getpid(), 1, (__pmCred *)&handshake); /* * At this point we know caller wants to set channel options and * pmcd supports them so go ahead and update the socket now (this * completes the SSL handshake in encrypting mode, authentication * via SASL, and/or enabling compression in NSS). */ if (sts >= 0 && pduflags) sts = __pmSecureClientHandshake(fd, pduflags, hostname, attrs); } else sts = PM_ERR_IPC; } else if (sts != PM_ERR_TIMEOUT) sts = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); return sts; }
int __pmLogChkLabel(__pmLogCtl *lcp, FILE *f, __pmLogLabel *lp, int vol) { int len; int version = UNKNOWN_VERSION; int xpectlen = sizeof(__pmLogLabel) + 2 * sizeof(len); int n; if (vol >= 0 && vol < lcp->l_numseen && lcp->l_seen[vol]) { /* FastPath, cached result of previous check for this volume */ fseek(f, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET); return 0; } if (vol >= 0 && vol >= lcp->l_numseen) { lcp->l_seen = (int *)realloc(lcp->l_seen, (vol+1)*(int)sizeof(lcp->l_seen[0])); if (lcp->l_seen == NULL) lcp->l_numseen = 0; else { int i; for (i = lcp->l_numseen; i < vol; i++) lcp->l_seen[i] = 0; lcp->l_numseen = vol+1; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "__pmLogChkLabel: fd=%d vol=%d", fileno(f), vol); #endif fseek(f, (long)0, SEEK_SET); n = (int)fread(&len, 1, sizeof(len), f); len = ntohl(len); if (n != sizeof(len) || len != xpectlen) { if (feof(f)) { clearerr(f); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " file is empty\n"); #endif return PM_ERR_NODATA; } else { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " header read -> %d (expect %d) or bad header len=%d (expected %d)\n", n, (int)sizeof(len), len, xpectlen); #endif if (ferror(f)) { clearerr(f); return -errno; } else return PM_ERR_LABEL; } } if ((n = (int)fread(lp, 1, sizeof(__pmLogLabel), f)) != sizeof(__pmLogLabel)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " bad label len=%d: expected %d\n", n, (int)sizeof(__pmLogLabel)); #endif if (ferror(f)) { clearerr(f); return -errno; } else return PM_ERR_LABEL; } else { /* swab internal log label */ lp->ill_magic = ntohl(lp->ill_magic); lp->ill_pid = ntohl(lp->ill_pid); lp->ill_start.tv_sec = ntohl(lp->ill_start.tv_sec); lp->ill_start.tv_usec = ntohl(lp->ill_start.tv_usec); lp->ill_vol = ntohl(lp->ill_vol); } n = (int)fread(&len, 1, sizeof(len), f); len = ntohl(len); if (n != sizeof(len) || len != xpectlen) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " trailer read -> %d (expect %d) or bad trailer len=%d (expected %d)\n", n, (int)sizeof(len), len, xpectlen); #endif if (ferror(f)) { clearerr(f); return -errno; } else return PM_ERR_LABEL; } version = lp->ill_magic & 0xff; if ((lp->ill_magic & 0xffffff00) != PM_LOG_MAGIC || (version != PM_LOG_VERS01 && version != PM_LOG_VERS02) || lp->ill_vol != vol) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " version %d not supported\n", version); #endif return PM_ERR_LABEL; } else { if (__pmSetVersionIPC(fileno(f), version) < 0) return -errno; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " [magic=%8x version=%d vol=%d pid=%d host=%s]\n", lp->ill_magic, version, lp->ill_vol, (int)lp->ill_pid, lp->ill_hostname); #endif } if (vol >= 0 && vol < lcp->l_numseen) lcp->l_seen[vol] = 1; return version; }