Ejemplo n.º 1
0
int
main(int argc, char **argv)
{
    char		*p;
    struct timeval	delta = { 1, 0 };

    if (argc != 2) _usage();

    __pmAFregister(&delta, NULL, timeout);
#ifdef DBG_TRACE_DESPERATE
    pmDebug |= DBG_TRACE_DESPERATE;
#endif

    for (p = argv[1]; *p; p++) {
	switch (*p) {
	    case 'i':
	    	fprintf(stderr, "initialize\n");
		PM_INIT_LOCKS();
		break;
	    case 'l':
	    	fprintf(stderr, "lock\n");
		PM_LOCK(__pmLock_libpcp);
		break;
	    case 'u':
	    	fprintf(stderr, "unlock\n");
		PM_UNLOCK(__pmLock_libpcp);
		break;
	    default:
		_usage();
	}
    }

    return 0;
}
Ejemplo n.º 2
0
Archivo: pdu.c Proyecto: rwongone/pcp
const struct timeval *
__pmDefaultRequestTimeout(void)
{
    static int		done_default = 0;

    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    if (!done_default) {
	char	*timeout_str;
	char	*end_ptr;
	if ((timeout_str = getenv("PMCD_REQUEST_TIMEOUT")) != NULL) {
	    def_timeout = strtod(timeout_str, &end_ptr);
	    if (*end_ptr != '\0' || def_timeout < 0.0) {
		__pmNotifyErr(LOG_WARNING,
			      "ignored bad PMCD_REQUEST_TIMEOUT = '%s'\n",
			      timeout_str);
	    }
	    else {
		__pmtimevalFromReal(def_timeout, &def_wait);
	    }
	}
	done_default = 1;
    }
    PM_UNLOCK(__pmLock_libpcp);
    return (&def_wait);
}
Ejemplo n.º 3
0
int
__pmSecureServerCertificateSetup(const char *db, const char *passwd, const char *cert_nickname)
{
    PM_INIT_LOCKS();
    PM_LOCK(secureserver_lock);

    /* Configure optional (cmdline) password file in case DB locked */
    secure_server.password_file = passwd;

    /*
     * Configure location of the NSS database with a sane default.
     * For servers, we default to the shared (sql) system-wide database.
     * If command line db specified, pass it directly through - allowing
     * any old database format, at the users discretion.
     */
    if (db) {
	/* shortened-buffer-size (-2) guarantees null-termination */
	strncpy(secure_server.database_path, db, MAXPATHLEN-2);
    }

    if (cert_nickname) {
	strncpy(secure_server.cert_nickname, cert_nickname, MAX_CERT_NAME_LENGTH-2);
    }
    else {
	strncpy(secure_server.cert_nickname, SECURE_SERVER_CERTIFICATE, MAX_CERT_NAME_LENGTH-2);
    }

    PM_UNLOCK(secureserver_lock);
    return 0;
}
Ejemplo n.º 4
0
Archivo: config.c Proyecto: Aconex/pcp
void
__pmConfig(__pmConfigCallback formatter)
{
    /*
     * Scan ${PCP_CONF-$PCP_DIR/etc/pcp.conf} and put all PCP config
     * variables found therein into the environment.
     */
    FILE *fp;
    char confpath[32];
    char dir[MAXPATHLEN];
    char var[MAXPATHLEN];
    char *prefix;
    char *conf;
    char *val;
    char *p;

    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    prefix = getenv("PCP_DIR");
    if ((conf = getenv("PCP_CONF")) == NULL) {
	strncpy(confpath, "/etc/pcp.conf", sizeof(confpath));
	if (prefix == NULL)
	    conf = __pmNativePath(confpath);
	else {
	    snprintf(dir, sizeof(dir),
			 "%s%s", prefix, __pmNativePath(confpath));
	    conf = dir;
	}
    }

    if (access((const char *)conf, R_OK) < 0 ||
	(fp = fopen(conf, "r")) == (FILE *)NULL) {
	char	errmsg[PM_MAXERRMSGLEN];
	pmprintf("FATAL PCP ERROR: could not open config file \"%s\" : %s\n",
		conf, osstrerror_r(errmsg, sizeof(errmsg)));
	pmprintf("You may need to set PCP_CONF or PCP_DIR in your environment.\n");
	pmflush();
	PM_UNLOCK(__pmLock_libpcp);
	exit(1);
    }

    while (fgets(var, sizeof(var), fp) != NULL) {
	if (var[0] == '#' || (p = strchr(var, '=')) == NULL)
	    continue;
	*p = '\0';
	val = p+1;
	if ((p = strrchr(val, '\n')) != NULL)
	    *p = '\0';
	if ((p = getenv(var)) != NULL)
	    val = p;
	else
	    formatter(var, prefix, val);

	if (pmDebug & DBG_TRACE_CONFIG)
	    fprintf(stderr, "pmGetConfig: (init) %s=%s\n", var, val);
    }
    fclose(fp);
    PM_UNLOCK(__pmLock_libpcp);
}
Ejemplo n.º 5
0
int
__pmUnpinPDUBuf(void *handle)
{
    bufctl_t	*pcp, pcp_search;
    void	*bcp;

    assert(((__psint_t)handle % sizeof(int)) == 0);
    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);

    /*
     * Initialize a dummy bufctl_t to use only as search key;
     * only its bc_buf & bc_size fields need to be set, as that's
     * all that bufctl_t_compare will look at.
     */
    pcp_search.bc_buf = handle;
    pcp_search.bc_size = 1;

    bcp = tfind(&pcp_search, &buf_tree, &bufctl_t_compare);
    /*
     * NB: don't release the lock until final disposition of this object;
     * we don't want to play TOCTOU.
     */
    if (likely(bcp != NULL)) {
	pcp = *(bufctl_t **)bcp;
    } else {
#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_PDUBUF) {
	    fprintf(stderr, "__pmUnpinPDUBuf(" PRINTF_P_PFX "%p) -> fails\n",
		    handle);
	    pdubufdump();
	}
#endif
	PM_UNLOCK(__pmLock_libpcp);
	return 0;
    }

#ifdef PCP_DEBUG
    if (unlikely(pmDebug & DBG_TRACE_PDUBUF))
	fprintf(stderr, "__pmUnpinPDUBuf(" PRINTF_P_PFX "%p) -> pdubuf="
			PRINTF_P_PFX "%p, pincnt=%d\n", handle,
		pcp->bc_buf, pcp->bc_pincnt - 1);
#endif

    assert((&pcp->bc_buf[0] <= (char*)handle) &&
	   ((char*)handle < &pcp->bc_buf[pcp->bc_size]));

    if (likely(--pcp->bc_pincnt == 0)) {
	tdelete(pcp, &buf_tree, &bufctl_t_compare);
	PM_UNLOCK(__pmLock_libpcp);
	free(pcp);
    }
    else {
	PM_UNLOCK(__pmLock_libpcp);
    }

    return 1;
}
Ejemplo n.º 6
0
static int
__pmSecureServerNegotiation(int fd, int *strength)
{
    PRIntervalTime timer;
    PRFileDesc *sslsocket;
    SECStatus secsts;
    int enabled, keysize;
    int msec;

    sslsocket = (PRFileDesc *)__pmGetSecureSocket(fd);
    if (!sslsocket)
	return PM_ERR_IPC;

    PM_INIT_LOCKS();
    PM_LOCK(secureserver_lock);
    secsts = SSL_ConfigSecureServer(sslsocket,
			secure_server.certificate,
			secure_server.private_key,
			secure_server.certificate_KEA);
    PM_UNLOCK(secureserver_lock);

    if (secsts != SECSuccess) {
	pmNotifyErr(LOG_ERR, "Unable to configure secure server: %s",
			    pmErrStr(__pmSecureSocketsError(PR_GetError())));
	return PM_ERR_IPC;
    }

    secsts = SSL_ResetHandshake(sslsocket, PR_TRUE /*server*/);
    if (secsts != SECSuccess) {
	pmNotifyErr(LOG_ERR, "Unable to reset secure handshake: %s",
			    pmErrStr(__pmSecureSocketsError(PR_GetError())));
	return PM_ERR_IPC;
    }

    /* Server initiates handshake now to get early visibility of errors */
    msec = __pmConvertTimeout(TIMEOUT_DEFAULT);
    timer = PR_MillisecondsToInterval(msec);
    secsts = SSL_ForceHandshakeWithTimeout(sslsocket, timer);
    if (secsts != SECSuccess) {
	pmNotifyErr(LOG_ERR, "Unable to force secure handshake: %s",
			    pmErrStr(__pmSecureSocketsError(PR_GetError())));
	return PM_ERR_IPC;
    }

    secsts = SSL_SecurityStatus(sslsocket, &enabled, NULL, &keysize, NULL, NULL, NULL);
    if (secsts != SECSuccess)
	return __pmSecureSocketsError(PR_GetError());

    *strength = (enabled > 0) ? keysize : DEFAULT_SECURITY_STRENGTH;
    return 0;
}
Ejemplo n.º 7
0
Archivo: connect.c Proyecto: tongfw/pcp
void
__pmConnectGetPorts(pmHostSpec *host)
{
    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    load_pmcd_ports();
    if (__pmAddHostPorts(host, global_portlist, global_nports) < 0) {
	__pmNotifyErr(LOG_WARNING,
		"__pmConnectGetPorts: portlist dup failed, "
		"using default PMCD_PORT (%d)\n", SERVER_PORT);
	host->ports[0] = SERVER_PORT;
	host->nports = 1;
    }
    PM_UNLOCK(__pmLock_libpcp);
}
Ejemplo n.º 8
0
int
__pmPtrToHandle(__pmContext *ctxp)
{
    int		i;
    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    for (i = 0; i < contexts_len; i++) {
	if (ctxp == contexts[i]) {
	    PM_UNLOCK(__pmLock_libpcp);
	    return i;
	}
    }
    PM_UNLOCK(__pmLock_libpcp);
    return PM_CONTEXT_UNDEF;
}
Ejemplo n.º 9
0
void
__pmCountPDUBuf(int need, int *alloc, int *free)
{
    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);

    pdu_bufcnt_need = need;
    pdu_bufcnt = 0;
    twalk(buf_tree, &pdubufcount);
    *alloc = pdu_bufcnt;

    *free = 0;			/* We don't retain freed nodes. */

    PM_UNLOCK(__pmLock_libpcp);
}
Ejemplo n.º 10
0
__pmPDU *
__pmFindPDUBuf(int need)
{
    bufctl_t	*pcp;
    void	*bcp;

    PM_INIT_LOCKS();

    if (unlikely(need < 0)) {
	/* special diagnostic case ... dump buffer state */
#ifdef PCP_DEBUG
	fprintf(stderr, "__pmFindPDUBuf(DEBUG)\n");
	pdubufdump();
#endif
	return NULL;
    }

    if ((pcp = (bufctl_t *)malloc(sizeof(*pcp) + need)) == NULL) {
	return NULL;
    }

    pcp->bc_pincnt = 1;
    pcp->bc_size = need;
    pcp->bc_buf = ((char *)pcp) + sizeof(*pcp);

    PM_LOCK(__pmLock_libpcp);
    /* Insert the node in the tree. */
    bcp = tsearch((void *)pcp, &buf_tree, &bufctl_t_compare);
    if (unlikely(bcp == NULL)) {	/* ENOMEM */
	PM_UNLOCK(__pmLock_libpcp);
	free(pcp);
	return NULL;
    }
    PM_UNLOCK(__pmLock_libpcp);

#ifdef PCP_DEBUG
    if (unlikely(pmDebug & DBG_TRACE_PDUBUF)) {
	fprintf(stderr, "__pmFindPDUBuf(%d) -> " PRINTF_P_PFX "%p\n",
		need, pcp->bc_buf);
	pdubufdump();
    }
#endif

    return (__pmPDU *)pcp->bc_buf;
}
Ejemplo n.º 11
0
/*
 * On success, context is locked and caller should unlock it
 */
__pmContext *
__pmHandleToPtr(int handle)
{
    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    if (handle < 0 || handle >= contexts_len ||
	contexts[handle]->c_type == PM_CONTEXT_FREE) {
	PM_UNLOCK(__pmLock_libpcp);
	return NULL;
    }
    else {
	__pmContext	*sts;
	sts = contexts[handle];
	PM_UNLOCK(__pmLock_libpcp);
	PM_LOCK(sts->c_lock);
	return sts;
    }
}
Ejemplo n.º 12
0
static char *
pmgetconfig(const char *name, int fatal)
{
    /*
     * state controls one-trip initialization, and recursion guard
     * for pathological failures in initialization
     */
    static int		state = 0;
    char		*val;

    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    if (state == 0) {
	state = 1;
	PM_UNLOCK(__pmLock_libpcp);
	__pmconfig(__pmNativeConfig, fatal);
	PM_LOCK(__pmLock_libpcp);
	state = 2;
    }
    else if (state == 1) {
	/* recursion from error in __pmConfig() ... no value is possible */
	PM_UNLOCK(__pmLock_libpcp);
	if (pmDebug & DBG_TRACE_CONFIG)
	    fprintf(stderr, "pmgetconfig: %s= ... recursion error\n", name);
	if (!fatal)
	    return NULL;
	val = "";
	return val;
    }
    PM_UNLOCK(__pmLock_libpcp);

    if ((val = getenv(name)) == NULL) {
	if (!fatal)
	    return NULL;
	val = "";
    }

    if (pmDebug & DBG_TRACE_CONFIG)
	fprintf(stderr, "pmgetconfig: %s=%s\n", name, val);

    return val;
}
Ejemplo n.º 13
0
void
__pmSecureServerShutdown(void)
{
    PM_INIT_LOCKS();
    PM_LOCK(secureserver_lock);
    if (secure_server.certificate) {
	CERT_DestroyCertificate(secure_server.certificate);
	secure_server.certificate = NULL;
    }
    if (secure_server.private_key) {
	SECKEY_DestroyPrivateKey(secure_server.private_key);
	secure_server.private_key = NULL;
    }
    if (secure_server.ssl_session_cache_setup) {
	SSL_ShutdownServerSessionIDCache();
	secure_server.ssl_session_cache_setup = 0;
    }    
    if (secure_server.initialized) {
	NSS_Shutdown();
	secure_server.initialized = 0;
    }
    PM_UNLOCK(secureserver_lock);
}
Ejemplo n.º 14
0
int
__pmSecureServerSetup(const char *db, const char *passwd)
{
    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);

    /* Configure optional (cmdline) password file in case DB locked */
    secure_server.password_file = passwd;

    /*
     * Configure location of the NSS database with a sane default.
     * For servers, we default to the shared (sql) system-wide database.
     * If command line db specified, pass it directly through - allowing
     * any old database format, at the users discretion.
     */
    if (db) {
	/* shortened-buffer-size (-2) guarantees null-termination */
	strncpy(secure_server.database_path, db, MAXPATHLEN-2);
    }

    PM_UNLOCK(__pmLock_libpcp);
    return 0;
}
Ejemplo n.º 15
0
int
pmWhichContext(void)
{
    /*
     * return curcontext, provided it is defined
     */
    int		sts;

    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    if (PM_TPD(curcontext) > PM_CONTEXT_UNDEF)
	sts = PM_TPD(curcontext);
    else
	sts = PM_ERR_NOCONTEXT;

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_CONTEXT)
	fprintf(stderr, "pmWhichContext() -> %d, cur=%d\n",
	    sts, PM_TPD(curcontext));
#endif
    PM_UNLOCK(__pmLock_libpcp);
    return sts;
}
Ejemplo n.º 16
0
static char *
certificate_database_password(PK11SlotInfo *info, PRBool retry, void *arg)
{
    size_t length = MAX_NSSDB_PASSWORD_LENGTH;
    char *password = NULL;
    char passfile[MAXPATHLEN];
    int sts;

    (void)arg;
    (void)info;

    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    passfile[0] = '\0';
    if (secure_server.password_file)
	strncpy(passfile, secure_server.password_file, MAXPATHLEN-1);
    passfile[MAXPATHLEN-1] = '\0';
    PM_UNLOCK(__pmLock_libpcp);

    if (passfile[0] == '\0') {
	__pmNotifyErr(LOG_ERR, "Password sought but no password file given");
	return NULL;
    }
    if (retry) {
	__pmNotifyErr(LOG_ERR, "Retry attempted during password extraction");
	return NULL;	/* no soup^Wretries for you */
    }

    sts = secure_file_contents(passfile, &password, &length);
    if (sts < 0) {
	__pmNotifyErr(LOG_ERR, "Cannot read password file \"%s\": %s",
			passfile, pmErrStr(sts));
	return NULL;
    }
    return password;
}
Ejemplo n.º 17
0
int
__pmSecureServerInit(void)
{
    const PRUint16 *cipher;
    SECStatus secsts;
    int pathSpecified;
    int sts = 0;

    PM_INIT_LOCKS();
    PM_LOCK(secureserver_lock);

    /* Only attempt this once. */
    if (secure_server.initialized)
	goto done;
    secure_server.initialized = 1;

    if (PR_Initialized() != PR_TRUE)
	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);

    /* Configure optional (cmdline) password file in case DB locked */
    PK11_SetPasswordFunc(certificate_database_password);

    /*
     * Configure location of the NSS database with a sane default.
     * For servers, we default to the shared (sql) system-wide database.
     * If command line db specified, pass it directly through - allowing
     * any old database format, at the users discretion.
     */
    if (!secure_server.database_path[0]) {
	const char *path;
	pathSpecified = 0;
	path = serverdb(secure_server.database_path, MAXPATHLEN, "sql:");

	/* this is the default case on some platforms, so no log spam */
	if (access(path, R_OK|X_OK) < 0) {
	    if (pmDebugOptions.context)
		pmNotifyErr(LOG_INFO,
			      "Cannot access system security database: %s",
			      secure_server.database_path);
	    sts = -EOPNOTSUPP;	/* not fatal - just no secure connections */
	    secure_server.init_failed = 1;
	    goto done;
	}
    }
    else
	pathSpecified = 1;

    /*
     * pmproxy acts as both a client and server. Since the
     * server init path happens first, the db previously
     * got opened readonly.  Instead try to open RW.
     * Fallback if there is an error.
     */

    secsts = NSS_InitReadWrite(secure_server.database_path);

    if( secsts != SECSuccess )
    	secsts = NSS_Init(secure_server.database_path);

    if (secsts != SECSuccess && !pathSpecified) {
	/* fallback, older versions of NSS do not support sql: */
	serverdb(secure_server.database_path, MAXPATHLEN, "");
	secsts = NSS_Init(secure_server.database_path);
    }

    if (secsts != SECSuccess) {
	pmNotifyErr(LOG_ERR, "Cannot setup certificate DB (%s): %s",
			secure_server.database_path,
			pmErrStr(__pmSecureSocketsError(PR_GetError())));
	sts = -EOPNOTSUPP;	/* not fatal - just no secure connections */
	secure_server.init_failed = 1;
	goto done;
    }

    /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */
    for (cipher = SSL_GetImplementedCiphers(); *cipher != 0; ++cipher)
	SSL_CipherPolicySet(*cipher, SSL_ALLOWED);

    /* Configure SSL session cache for multi-process server, using defaults */
    secsts = SSL_ConfigMPServerSIDCache(1, 0, 0, NULL);
    if (secsts != SECSuccess) {
	pmNotifyErr(LOG_ERR, "Unable to configure SSL session ID cache: %s",
		pmErrStr(__pmSecureSocketsError(PR_GetError())));
	sts = -EOPNOTSUPP;	/* not fatal - just no secure connections */
	secure_server.init_failed = 1;
	goto done;
    } else {
	secure_server.ssl_session_cache_setup = 1;
    }

    /*
     * Iterate over any/all PCP Collector nickname certificates,
     * seeking one valid certificate.  No-such-nickname is not an
     * error (not configured by admin at all) but anything else is.
     */
    CERTCertList *certlist;
    CERTCertDBHandle *nssdb = CERT_GetDefaultCertDB();
    CERTCertificate *dbcert = PK11_FindCertFromNickname(secure_server.cert_nickname, NULL);

    if (dbcert) {
	PRTime now = PR_Now();
	SECItem *name = &dbcert->derSubject;
	CERTCertListNode *node;

	certlist = CERT_CreateSubjectCertList(NULL, nssdb, name, now, PR_FALSE);
	if (certlist) {
	    for (node = CERT_LIST_HEAD(certlist);
		 !CERT_LIST_END(node, certlist);
		 node = CERT_LIST_NEXT (node)) {
		if (pmDebugOptions.context)
		    __pmDumpCertificate(stderr, secure_server.cert_nickname, node->cert);
		if (!__pmValidCertificate(nssdb, node->cert, now))
		    continue;
		secure_server.certificate_verified = 1;
		break;
	    }
	    CERT_DestroyCertList(certlist);
	}

	if (secure_server.certificate_verified) {
	    secure_server.certificate_KEA = NSS_FindCertKEAType(dbcert);
	    secure_server.private_key = PK11_FindKeyByAnyCert(dbcert, NULL);
	    if (!secure_server.private_key) {
		pmNotifyErr(LOG_ERR, "Unable to extract %s private key",
				secure_server.cert_nickname);
		CERT_DestroyCertificate(dbcert);
		secure_server.certificate_verified = 0;
		sts = -EOPNOTSUPP;	/* not fatal - just no secure connections */
		secure_server.init_failed = 1;
		goto done;
	    }
	} else {
	    pmNotifyErr(LOG_ERR, "Unable to find a valid %s", secure_server.cert_nickname);
	    CERT_DestroyCertificate(dbcert);
	    sts = -EOPNOTSUPP;	/* not fatal - just no secure connections */
	    secure_server.init_failed = 1;
	    goto done;
	}
    }

    if (! secure_server.certificate_verified) {
	if (pmDebugOptions.context) {
	    pmNotifyErr(LOG_INFO, "No valid %s in security database: %s",
			  secure_server.cert_nickname, secure_server.database_path);
	}
	sts = -EOPNOTSUPP;	/* not fatal - just no secure connections */
	secure_server.init_failed = 1;
	goto done;
    }

    secure_server.certificate = dbcert;
    secure_server.init_failed = 0;
    sts = 0;

done:
    PM_UNLOCK(secureserver_lock);
    return sts;
}
Ejemplo n.º 18
0
int
__pmConnectLocal(__pmHashCtl *attrs)
{
    int			i;
    __pmDSO		*dp;
    char		pathbuf[MAXPATHLEN];
    const char		*path;
#if defined(HAVE_DLOPEN)
    unsigned int	challenge;
    void		(*initp)(pmdaInterface *);
#ifdef HAVE_ATEXIT
    static int		atexit_installed = 0;
#endif
#endif

    if (numdso == -1) {
	int	sts;
	sts = build_dsotab();
	if (sts < 0) return sts;
    }

    for (i = 0; i < numdso; i++) {
	dp = &dsotab[i];
	if (dp->domain == -1 || dp->handle != NULL)
	    continue;
	/*
	 * __pmLocalPMDA() means the path to the DSO may be something
	 * other than relative to $PCP_PMDAS_DIR ... need to try both
	 * options and also with and without DSO_SUFFIX (so, dll, etc)
	 */
	snprintf(pathbuf, sizeof(pathbuf), "%s%c%s",
		 pmGetConfig("PCP_PMDAS_DIR"), __pmPathSeparator(), dp->name);
	if ((path = __pmFindPMDA(pathbuf)) == NULL) {
	    snprintf(pathbuf, sizeof(pathbuf), "%s%c%s.%s",
		 pmGetConfig("PCP_PMDAS_DIR"), __pmPathSeparator(), dp->name, DSO_SUFFIX);
	    if ((path = __pmFindPMDA(pathbuf)) == NULL) {
		if ((path = __pmFindPMDA(dp->name)) == NULL) {
		    snprintf(pathbuf, sizeof(pathbuf), "%s.%s", dp->name, DSO_SUFFIX);
		    if ((path = __pmFindPMDA(pathbuf)) == NULL) {
			pmprintf("__pmConnectLocal: Warning: cannot find DSO at \"%s\" or \"%s\"\n", 
			     pathbuf, dp->name);
			pmflush();
			dp->domain = -1;
			dp->handle = NULL;
			continue;
		    }
		}
	    }
	}
#if defined(HAVE_DLOPEN)
	dp->handle = dlopen(path, RTLD_NOW);
	if (dp->handle == NULL) {
	    pmprintf("__pmConnectLocal: Warning: error attaching DSO "
		     "\"%s\"\n%s\n\n", path, dlerror());
	    pmflush();
	    dp->domain = -1;
	}
#else	/* ! HAVE_DLOPEN */
	dp->handle = NULL;
	pmprintf("__pmConnectLocal: Warning: error attaching DSO \"%s\"\n",
		 path);
	pmprintf("No dynamic DSO/DLL support on this platform\n\n");
	pmflush();
	dp->domain = -1;
#endif

	if (dp->handle == NULL)
	    continue;

#if defined(HAVE_DLOPEN)
	/*
	 * rest of this only makes sense if the dlopen() worked
	 */
	if (dp->init == NULL)
	    initp = NULL;
	else
	    initp = (void (*)(pmdaInterface *))dlsym(dp->handle, dp->init);
	if (initp == NULL) {
	    pmprintf("__pmConnectLocal: Warning: couldn't find init function "
		     "\"%s\" in DSO \"%s\"\n", dp->init, path);
	    pmflush();
	    dlclose(dp->handle);
	    dp->domain = -1;
	    continue;
	}

	/*
	 * Pass in the expected domain id.
	 * The PMDA initialization routine can (a) ignore it, (b) check it
	 * is the expected value, or (c) self-adapt.
	 */
	dp->dispatch.domain = dp->domain;

	/*
	 * the PMDA interface / PMAPI version discovery as a "challenge" ...
	 * for pmda_interface it is all the bits being set,
	 * for pmapi_version it is the complement of the one you are using now
	 */
	challenge = 0xff;
	dp->dispatch.comm.pmda_interface = challenge;
	dp->dispatch.comm.pmapi_version = ~PMAPI_VERSION;
	dp->dispatch.comm.flags = 0;
	dp->dispatch.status = 0;

	(*initp)(&dp->dispatch);

	if (dp->dispatch.status != 0) {
	    /* initialization failed for some reason */
	    char	errmsg[PM_MAXERRMSGLEN];
	    pmprintf("__pmConnectLocal: Warning: initialization "
		     "routine \"%s\" failed in DSO \"%s\": %s\n", 
		     dp->init, path, pmErrStr_r(dp->dispatch.status, errmsg, sizeof(errmsg)));
	    pmflush();
	    dlclose(dp->handle);
	    dp->domain = -1;
	}
	else {
	    if (dp->dispatch.comm.pmda_interface < PMDA_INTERFACE_2 ||
		dp->dispatch.comm.pmda_interface > PMDA_INTERFACE_LATEST) {
		pmprintf("__pmConnectLocal: Error: Unknown PMDA interface "
			 "version %d in \"%s\" DSO\n", 
			 dp->dispatch.comm.pmda_interface, path);
		pmflush();
		dlclose(dp->handle);
		dp->domain = -1;
	    }
	    else if (dp->dispatch.comm.pmapi_version != PMAPI_VERSION_2) {
		pmprintf("__pmConnectLocal: Error: Unknown PMAPI version %d "
			 "in \"%s\" DSO\n",
			 dp->dispatch.comm.pmapi_version, path);
		pmflush();
		dlclose(dp->handle);
		dp->domain = -1;
	    }
	    else if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_6 &&
		    (dp->dispatch.comm.flags & PDU_FLAG_AUTH) != 0) {
		/* Agent wants to know about connection attributes */
		build_dsoattrs(&dp->dispatch, attrs);
	    }
	}
#ifdef HAVE_ATEXIT
	PM_INIT_LOCKS();
	PM_LOCK(__pmLock_libpcp);
	if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5 &&
	    atexit_installed == 0) {
	    /* install end of local context handler */
	    atexit(EndLocalContext);
	    atexit_installed = 1;
	}
	PM_UNLOCK(__pmLock_libpcp);
#endif
#endif	/* HAVE_DLOPEN */
    }

    return 0;
}
Ejemplo n.º 19
0
Archivo: pdu.c Proyecto: 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;
}
Ejemplo n.º 20
0
Archivo: connect.c Proyecto: tongfw/pcp
int
__pmConnectPMCD(pmHostSpec *hosts, int nhosts, int ctxflags, __pmHashCtl *attrs)
{
    int		sts = -1;
    int		fd = -1;	/* Fd for socket connection to pmcd */
    int		*ports;
    int		nports;
    int		portIx;
    int		version = -1;
    int		proxyport;
    pmHostSpec	*proxyhost;

    static int first_time = 1;
    static pmHostSpec proxy;

    PM_INIT_LOCKS();
    PM_LOCK(__pmLock_libpcp);
    if (first_time) {
	/*
	 * One-trip check for use of pmproxy(1) in lieu of pmcd(1),
	 * and to extract the optional environment variables ...
	 * PMCD_PORT, PMPROXY_HOST and PMPROXY_PORT.
	 * We also check for the presense of a certificate database
	 * and load it up if either a user or system (global) DB is
	 * found.
	 */
	first_time = 0;
	load_pmcd_ports();
	load_proxy_hostspec(&proxy);
    }

    if (hosts[0].nports == 0) {
	nports = global_nports;
	ports = global_portlist;
    }
    else {
	nports = hosts[0].nports;
	ports = hosts[0].ports;
    }

    if (proxy.name == NULL && nhosts == 1) {
	const char *name = (const char *)hosts[0].name;

	/*
	 * no proxy, connecting directly to pmcd
	 */
	PM_UNLOCK(__pmLock_libpcp);

	sts = -1;
	/* Try connecting via the local unix domain socket, if requested and supported. */
	if (nports == PM_HOST_SPEC_NPORTS_LOCAL || nports == PM_HOST_SPEC_NPORTS_UNIX) {
#if defined(HAVE_STRUCT_SOCKADDR_UN)
	    if ((fd = __pmAuxConnectPMCDUnixSocket(name)) >= 0) {
		if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) {
		    __pmCloseSocket(fd);
		}
		else
		    sts = fd;
		portIx = -1; /* no port */
	    }
#endif
	    /*
	     * If the connection failed, or is not supported, and the protocol was 'local:',
	     * then try connecting to localhost via the default port(s).
	     */
	    if (sts < 0) {
		if (nports == PM_HOST_SPEC_NPORTS_LOCAL) {
		    name = "localhost";
		    nports = global_nports;
		    ports = global_portlist;
		    sts = -1; /* keep trying */
		}
		else
		    sts = -2; /* no more connection attempts. */
	    }
	}

	/* If still not connected, try via the given host name and ports, if requested. */
	if (sts == -1) {
	    for (portIx = 0; portIx < nports; portIx++) {
		if ((fd = __pmAuxConnectPMCDPort(name, ports[portIx])) >= 0) {
		    if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) {
			__pmCloseSocket(fd);
		    }
		    else
			/* success */
			break;
		}
		else
		    sts = fd;
	    }
	}

	if (sts < 0) {
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_CONTEXT) {
		char	errmsg[PM_MAXERRMSGLEN];
		fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=",
		   hosts[0].name);
		for (portIx = 0; portIx < nports; portIx++) {
		    if (portIx == 0) fprintf(stderr, "%d", ports[portIx]);
		    else fprintf(stderr, ",%d", ports[portIx]);
		}
		fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg)));
	    }
#endif
	    return sts;
	}

#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_CONTEXT) {
	    if (portIx >= 0) {
		fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=%d fd=%d PDU version=%u\n",
			hosts[0].name, ports[portIx], fd, __pmVersionIPC(fd));
	    }
	    else {
		fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection path=%s fd=%d PDU version=%u\n",
			hosts[0].name, name, fd, __pmVersionIPC(fd));
	    }
	    __pmPrintIPC();
	}
#endif

	return fd;
    }

    /*
     * connecting to pmproxy, and then to pmcd ... not a direct
     * connection to pmcd
     */
    proxyhost = (nhosts > 1) ? &hosts[1] : &proxy;
    proxyport = (proxyhost->nports > 0) ? proxyhost->ports[0] : PROXY_PORT;

    for (portIx = 0; portIx < nports; portIx++) {
	fd = __pmAuxConnectPMCDPort(proxyhost->name, proxyport);
	if (fd < 0) {
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_CONTEXT) {
		char	errmsg[PM_MAXERRMSGLEN];
		fprintf(stderr, "__pmConnectPMCD(%s): proxy to %s port=%d failed: %s \n",
			hosts[0].name, proxyhost->name, proxyport, pmErrStr_r(-neterror(), errmsg, sizeof(errmsg)));
	    }
#endif
	    PM_UNLOCK(__pmLock_libpcp);
	    return fd;
	}
	if ((sts = version = negotiate_proxy(fd, hosts[0].name, ports[portIx])) < 0)
	    __pmCloseSocket(fd);
	else if ((sts = __pmConnectHandshake(fd, proxyhost->name, ctxflags, attrs)) < 0)
	    __pmCloseSocket(fd);
	else
	    /* success */
	    break;
    }

    if (sts < 0) {
#ifdef PCP_DEBUG
	if (pmDebug & DBG_TRACE_CONTEXT) {
	    char	errmsg[PM_MAXERRMSGLEN];
	    fprintf(stderr, "__pmConnectPMCD(%s): proxy connection to %s port=",
			hosts[0].name, proxyhost->name);
	    for (portIx = 0; portIx < nports; portIx++) {
		if (portIx == 0) fprintf(stderr, "%d", ports[portIx]);
		else fprintf(stderr, ",%d", ports[portIx]);
	    }
	    fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg)));
	}
#endif
	PM_UNLOCK(__pmLock_libpcp);
	return sts;
    }

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_CONTEXT) {
	fprintf(stderr, "__pmConnectPMCD(%s): proxy connection host=%s port=%d fd=%d version=%d\n",
	    hosts[0].name, proxyhost->name, ports[portIx], fd, version);
    }
#endif

    PM_UNLOCK(__pmLock_libpcp);
    return fd;
}