The tcp_getcred(), tcp6_getcred(), udp_getcred(), udp6_getcred() look
like a bad example of mostly duplicated code caused by cut and paste
programming.  By passing a pointer to the inpcbinfo structure as an
argument to the sysctl hander it is possible to combine the use a common
handler for the TCP and UDP cases, and the IPv4 and IPv6 handlers can
use a common back end once the PCB has been looked up.

To switch tcp_getcred() to use this new handler, you would make the
following change:

 SYSCTL_PROC(_net_inet_tcp, OID_AUTO, getcred,
-    CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0,
-    tcp_getcred, "S,xucred", "Get the xucred of a TCP connection");
+    CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_PRISON, &tcbinfo, 0,
+    in_pcbgetcred_handler, "S,xucred", "Get the xucred of a TCP connection");


The pcblist sysctl handlers look like another case of cut and paste
programming ...


=======================Cut Here===========================
#include "opt_inet6.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/jail.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/ucred.h>

#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/in_pcbgetcred.h>
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/in6_pcb.h>
#endif /* INET6 */


/*
 * Convert the socket credential for inp to external format, unlock pcbinfo,
 * and return the credential info using SYSCTL_OUT().
 */
static int
in_getcred(struct sysctl_req *req, struct inpcbinfo *pcbinfo, struct inpcb *inp,
    int s)
{
        struct xucred xuc;
        int error;

        if (inp == NULL) {
                error = ENOENT;
                goto out;
        }
        /*
         * XXX - It should not be necessary to lock the PCB or
         *       test inp_socket, since inp_socket is static
         *       for the life of the PCB.
         */
        INP_LOCK(inp);
        if (inp->inp_socket == NULL) {
                error = ENOENT;
                goto outlocked;
        }
        error = cr_canseesocket(req->td->td_ucred, inp->inp_socket);
        if (error == 0)
                cru2x(inp->inp_socket->so_cred, &xuc);
outlocked:
        INP_UNLOCK(inp);
out:
        INP_INFO_RUNLOCK(pcbinfo);
        splx(s);
        if (error == 0)
                error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
        return (error);
}

/*
 * Socket credential sysctl handler.
 * The pcbinfo pointer should be passed as arg1.
 */
int
in_pcbgetcred_handler(SYSCTL_HANDLER_ARGS)
{
        struct inpcbinfo *pcbinfo = arg1;
        struct sockaddr_in addrs[2];
        struct inpcb *inp;
        int error, s;

        error = suser_cred(req->td->td_ucred, PRISON_ROOT);
        if (error)
                return (error);
        error = SYSCTL_IN(req, addrs, sizeof(addrs));
        if (error)
                return (error);
        s = splnet();
        INP_INFO_RLOCK(pcbinfo);
        inp = in_pcblookup_hash(pcbinfo, addrs[1].sin_addr, addrs[1].sin_port,
            addrs[0].sin_addr, addrs[0].sin_port, 0, NULL);
        return (in_getcred(req, pcbinfo, inp, s));
}

#ifdef INET6
int
in6_pcbgetcred_handler(SYSCTL_HANDLER_ARGS)
{
        struct inpcbinfo *pcbinfo = arg1;
        struct sockaddr_in6 addrs[2];
        struct inpcb *inp;
        int error, s, mapped = 0;

        error = suser_cred(req->td->td_ucred, PRISON_ROOT);
        if (error)
                return (error);
        error = SYSCTL_IN(req, addrs, sizeof(addrs));
        if (error)
                return (error);
        if (IN6_IS_ADDR_V4MAPPED(&addrs[0].sin6_addr)) {
                if (IN6_IS_ADDR_V4MAPPED(&addrs[1].sin6_addr))
                        mapped = 1;
                else
                        return (EINVAL);
        }
        s = splnet();
        INP_INFO_RLOCK(pcbinfo);
        if (mapped == 1)
                inp = in_pcblookup_hash(pcbinfo,
                        *(struct in_addr *)&addrs[1].sin6_addr.s6_addr[12],
                        addrs[1].sin6_port,
                        *(struct in_addr *)&addrs[0].sin6_addr.s6_addr[12],
                        addrs[0].sin6_port,
                        0, NULL);
        else
                inp = in6_pcblookup_hash(pcbinfo, &addrs[1].sin6_addr,
                                 addrs[1].sin6_port,
                                 &addrs[0].sin6_addr, addrs[0].sin6_port,
                                 0, NULL);
        return (in_getcred(req, pcbinfo, inp, s));
}
#endif
=======================Cut Here===========================


To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to