<commit_before>/*
 * Copyright (c) 2012-2015 Red Hat.
 * Copyright (c) 1995-2000,2003,2004 Silicon Graphics, Inc.  All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 */

#include "pmapi.h"
#include "impl.h"
#include "pmda.h"
#include "libdefs.h"
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif

/*
 * Open an inet port to PMCD
 */

static void
__pmdaOpenSocket(char *sockname, int port, int family, int *infd, int *outfd)
{
    int			sts;
    int			sfd;
    struct servent	*service;
    __pmSockAddr	*myaddr;
    __pmSockLen		addrlen;
    __pmFdSet		rfds;
    int			one = 1;

    if (sockname != NULL) {	/* Translate port name to port num */
	service = getservbyname(sockname, NULL);
	if (service == NULL) {
	    __pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: getservbyname(%s): %s\n", 
		    sockname, netstrerror());
	    exit(1);
	}
	port = service->s_port;
    }

    if (family != AF_INET6) {
	sfd = __pmCreateSocket();
	if (sfd < 0) {
	    __pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: inet socket: %s\n",
			  netstrerror());
	    exit(1);
	}
    }
    else {
	sfd = __pmCreateIPv6Socket();
	if (sfd < 0) {
	    __pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: ipv6 socket: %s\n",
			  netstrerror());
	    exit(1);
	}
    }
#ifndef IS_MINGW
    /*
     * allow port to be quickly re-used, e.g. when Install and PMDA already
     * installed, this becomes terminate and restart in a hurry ...
     */
    if (__pmSetSockOpt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
		(__pmSockLen)sizeof(one)) < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: __pmSetSockOpt(reuseaddr): %s\n",
			netstrerror());
	exit(1);
    }
#else
    /* see MSDN tech note: "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" */
    if (__pmSetSockOpt(sfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&one,
		(__pmSockLen)sizeof(one)) < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: __pmSetSockOpt(excladdruse): %s\n",
			netstrerror());
	exit(1);
    }
#endif

    if ((myaddr =__pmSockAddrAlloc()) == NULL) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: sock addr alloc failed\n");
	exit(1);
    }
    __pmSockAddrInit(myaddr, family, INADDR_LOOPBACK, port);
    sts = __pmBind(sfd, (void *)myaddr, __pmSockAddrSize());
    if (sts < 0) {
	__pmSockAddrFree(myaddr);
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: bind: %s\n",
			netstrerror());
	exit(1);
    }

    sts = __pmListen(sfd, 1);	/* Max. 1 pending connection request (pmcd) */
    if (sts == -1) {
        __pmSockAddrFree(myaddr);
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: listen: %s\n",
			netstrerror());
	exit(1);
    }

    /* block here indefinitely, waiting for a connection */
    __pmFD_ZERO(&rfds);
    __pmFD_SET(sfd, &rfds);
    if ((sts = __pmSelectRead(sfd+1, &rfds, NULL)) != 1) {
        sts = (sts < 0) ? -neterror() : -EINVAL;
    }
    if (sts < 0) {
        __pmSockAddrFree(myaddr);
        __pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: select: %s\n",
                        pmErrStr(sts));
        exit(1);
    }

    addrlen = __pmSockAddrSize();
    if ((*infd = __pmAccept(sfd, myaddr, &addrlen)) < 0) {
        __pmSockAddrFree(myaddr);
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: accept: %s\n",
			netstrerror());
	exit(1);
    }
    __pmCloseSocket(sfd);
    __pmSetSocketIPC(*infd);
    __pmSockAddrFree(myaddr);

    *outfd = *infd;
}

static void
__pmdaOpenInet(char *sockname, int port, int *infd, int *outfd)
{
    __pmdaOpenSocket(sockname, port, AF_INET, infd, outfd);
}

static void
__pmdaOpenIPv6(char *sockname, int port, int *infd, int *outfd)
{
    __pmdaOpenSocket(sockname, port, AF_INET6, infd, outfd);
}

#ifdef HAVE_STRUCT_SOCKADDR_UN
/*
 * Open a unix port to PMCD
 */
static void
__pmdaOpenUnix(char *sockname, int *infd, int *outfd)
{
    int			sts;
    int			sfd;
    int			len;
    __pmSockLen		addrlen;
    struct sockaddr_un	myaddr;
    struct sockaddr_un	from;

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: Unix domain socket: %s",
		     netstrerror());
	exit(1);
    }
    /* Sockets in the Unix domain are named pipes in the file system.
     * In case the socket is still hanging around, try to remove it.  If it
     * belonged to someone and is still open, they will still keep the
     * connection because the reference count is non-zero.
     */
    if ((sts = unlink(sockname)) == 0)
    	__pmNotifyErr(LOG_WARNING, "__pmdaOpenUnix: Unix domain socket '%s' existed, unlinked it\n",
		     sockname);
    else if (sts < 0 && oserror() != ENOENT) {
	/* If can't unlink socket, give up.  We might end up with an
	 * unwanted connection to some other socket (from outer space)
	 */
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: Unlinking Unix domain socket '%s': %s\n",
		     sockname, osstrerror());
	exit(1);
    }
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sun_family = AF_UNIX;
    strcpy(myaddr.sun_path, sockname);
    len = (int)offsetof(struct sockaddr_un, sun_path) + (int)strlen(myaddr.sun_path);
    sts = bind(sfd, (struct sockaddr*) &myaddr, len);
    if (sts < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: unix bind: %s\n",
			netstrerror());
	exit(1);
    }

    sts = listen(sfd, 5);	/* Max. of 5 pending connection requests */
    if (sts == -1) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: unix listen: %s\n",
			netstrerror());
	exit(1);
    }
    addrlen = sizeof(from);
    /* block here, waiting for a connection */
    if ((*infd = accept(sfd, (struct sockaddr *)&from, &addrlen)) < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: unix accept: %s\n",
			netstrerror());
	exit(1);
    }
    close(sfd);
    *outfd = *infd;
}
#else
static void
__pmdaOpenUnix(char *sockname, int *infd, int *outfd)
{
    __pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: UNIX domain sockets unsupported\n");
    exit(1);
}
#endif<commit_msg>libpcp_pmda: ensure af_unix socket ownership allows pmcd to read<commit_after>/*
 * Copyright (c) 2012-2016 Red Hat.
 * Copyright (c) 1995-2000,2003,2004 Silicon Graphics, Inc.  All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 */

#include "pmapi.h"
#include "impl.h"
#include "pmda.h"
#include "libdefs.h"
#include <sys/stat.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif

/*
 * Open an inet port to PMCD
 */

static void
__pmdaOpenSocket(char *sockname, int port, int family, int *infd, int *outfd)
{
    int			sts;
    int			sfd;
    struct servent	*service;
    __pmSockAddr	*myaddr;
    __pmSockLen		addrlen;
    __pmFdSet		rfds;
    int			one = 1;

    if (sockname != NULL) {	/* Translate port name to port num */
	service = getservbyname(sockname, NULL);
	if (service == NULL) {
	    __pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: getservbyname(%s): %s\n", 
		    sockname, netstrerror());
	    exit(1);
	}
	port = service->s_port;
    }

    if (family != AF_INET6) {
	sfd = __pmCreateSocket();
	if (sfd < 0) {
	    __pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: inet socket: %s\n",
			  netstrerror());
	    exit(1);
	}
    }
    else {
	sfd = __pmCreateIPv6Socket();
	if (sfd < 0) {
	    __pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: ipv6 socket: %s\n",
			  netstrerror());
	    exit(1);
	}
    }
#ifndef IS_MINGW
    /*
     * allow port to be quickly re-used, e.g. when Install and PMDA already
     * installed, this becomes terminate and restart in a hurry ...
     */
    if (__pmSetSockOpt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
		(__pmSockLen)sizeof(one)) < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: __pmSetSockOpt(reuseaddr): %s\n",
			netstrerror());
	exit(1);
    }
#else
    /* see MSDN tech note: "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" */
    if (__pmSetSockOpt(sfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&one,
		(__pmSockLen)sizeof(one)) < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: __pmSetSockOpt(excladdruse): %s\n",
			netstrerror());
	exit(1);
    }
#endif

    if ((myaddr =__pmSockAddrAlloc()) == NULL) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: sock addr alloc failed\n");
	exit(1);
    }
    __pmSockAddrInit(myaddr, family, INADDR_LOOPBACK, port);
    sts = __pmBind(sfd, (void *)myaddr, __pmSockAddrSize());
    if (sts < 0) {
	__pmSockAddrFree(myaddr);
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: bind: %s\n",
			netstrerror());
	exit(1);
    }

    sts = __pmListen(sfd, 1);	/* Max. 1 pending connection request (pmcd) */
    if (sts == -1) {
        __pmSockAddrFree(myaddr);
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: listen: %s\n",
			netstrerror());
	exit(1);
    }

    /* block here indefinitely, waiting for a connection */
    __pmFD_ZERO(&rfds);
    __pmFD_SET(sfd, &rfds);
    if ((sts = __pmSelectRead(sfd+1, &rfds, NULL)) != 1) {
        sts = (sts < 0) ? -neterror() : -EINVAL;
    }
    if (sts < 0) {
        __pmSockAddrFree(myaddr);
        __pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: select: %s\n",
                        pmErrStr(sts));
        exit(1);
    }

    addrlen = __pmSockAddrSize();
    if ((*infd = __pmAccept(sfd, myaddr, &addrlen)) < 0) {
        __pmSockAddrFree(myaddr);
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenSocket: accept: %s\n",
			netstrerror());
	exit(1);
    }
    __pmCloseSocket(sfd);
    __pmSetSocketIPC(*infd);
    __pmSockAddrFree(myaddr);

    *outfd = *infd;
}

static void
__pmdaOpenInet(char *sockname, int port, int *infd, int *outfd)
{
    __pmdaOpenSocket(sockname, port, AF_INET, infd, outfd);
}

static void
__pmdaOpenIPv6(char *sockname, int port, int *infd, int *outfd)
{
    __pmdaOpenSocket(sockname, port, AF_INET6, infd, outfd);
}

#ifdef HAVE_STRUCT_SOCKADDR_UN
/*
 * Setup appropriate permissions for the Unix domain socket file
 *
 * pmcd must be able to talk to us on this channel, and it may be running
 * as an unprivileged user by the time the PMDA runs this code - so, need
 * to set permissions such that PCP_USER can access this file too.
 */
static void
socket_ownership(char *sockname)
{
    char		*username = pmGetConfig("PCP_USER");
    char		errmsg[128];
    struct passwd	*pw;
    int			sts;

    setoserror(0);
    if ((pw = getpwnam(username)) == 0) {
	__pmNotifyErr(LOG_CRIT,
		"cannot find the %s user to change ownership to\n", username);
	exit(1);
    } else if (oserror() != 0) {
	__pmNotifyErr(LOG_CRIT, "getpwnam(%s) failed: %s\n",
		username, pmErrStr_r(oserror(), errmsg, sizeof(errmsg)));
	exit(1);
    }

    sts = chmod(sockname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    if (sts == -1) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: unix chmod on %s: %s\n",
			sockname, netstrerror());
	exit(1);
    }
    sts = chown(sockname, pw->pw_uid, pw->pw_gid);
    if (sts == -1) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: unix chown on %s: %s\n",
			sockname, netstrerror());
	exit(1);
    }
}

/*
 * Open a unix port to PMCD
 */
static void
__pmdaOpenUnix(char *sockname, int *infd, int *outfd)
{
    int			sts;
    int			sfd;
    int			len;
    __pmSockLen		addrlen;
    struct sockaddr_un	myaddr;
    struct sockaddr_un	from;

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: Unix domain socket: %s",
		     netstrerror());
	exit(1);
    }
    /* Sockets in the Unix domain are named pipes in the file system.
     * In case the socket is still hanging around, try to remove it.  If it
     * belonged to someone and is still open, they will still keep the
     * connection because the reference count is non-zero.
     */
    if ((sts = unlink(sockname)) == 0)
    	__pmNotifyErr(LOG_WARNING, "__pmdaOpenUnix: Unix domain socket '%s' existed, unlinked it\n",
		     sockname);
    else if (sts < 0 && oserror() != ENOENT) {
	/* If can't unlink socket, give up.  We might end up with an
	 * unwanted connection to some other socket (from outer space)
	 */
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: Unlinking Unix domain socket '%s': %s\n",
		     sockname, osstrerror());
	exit(1);
    }
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sun_family = AF_UNIX;
    strcpy(myaddr.sun_path, sockname);
    len = (int)offsetof(struct sockaddr_un, sun_path) + (int)strlen(myaddr.sun_path);
    sts = bind(sfd, (struct sockaddr*) &myaddr, len);
    if (sts < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: unix bind: %s\n",
			netstrerror());
	exit(1);
    }
    socket_ownership(sockname);

    sts = listen(sfd, 5);	/* Max. of 5 pending connection requests */
    if (sts == -1) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: unix listen: %s\n",
			netstrerror());
	exit(1);
    }
    addrlen = sizeof(from);
    /* block here, waiting for a connection */
    if ((*infd = accept(sfd, (struct sockaddr *)&from, &addrlen)) < 0) {
	__pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: unix accept: %s\n",
			netstrerror());
	exit(1);
    }
    close(sfd);
    *outfd = *infd;
}
#else
static void
__pmdaOpenUnix(char *sockname, int *infd, int *outfd)
{
    __pmNotifyErr(LOG_CRIT, "__pmdaOpenUnix: UNIX domain sockets unsupported\n");
    exit(1);
}
#endif
{'fraction_non_alphanumeric': 0.13233413837192784, 'fraction_numerical': 0.010939053842875409, 'mean_word_length': 3.444128787878788, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5599943', 'n_tokens_mistral': 5538, 'n_tokens_neox': 5282, 'n_words': 1402}