unsigned int __pmServerGetFeaturesFromPDU(__pmPDU *pb) { int version; int challenge; __pmPDUInfo pduinfo; int sts; unsigned int server_features=0; version = __pmDecodeXtendError(pb, &sts, &challenge); if( version >= 0 && version == PDU_VERSION2 && sts >=0 ){ pduinfo = __ntohpmPDUInfo(*(__pmPDUInfo *)&challenge); server_features = pduinfo.features; } return server_features; }
/* * 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; }