Beispiel #1
0
/*
 * Get other side's uid for UNIX socket.
 *
 * Standardise on getpeereid() from BSDs.
 */
int getpeereid(int fd, uid_t *uid_p, gid_t *gid_p)
{
#ifdef SO_PEERCRED
	struct ucred cred;
	socklen_t len = sizeof(cred);
	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) >= 0) {
		*uid_p = cred.uid;
		*gid_p = cred.gid;
		return 0;
	}
#else /* !SO_PEERCRED */
#ifdef HAVE_GETPEERUCRED
	ucred_t *cred = NULL;
	if (getpeerucred(fd, &cred) >= 0) {
		*uid_p = ucred_geteuid(cred);
		*gid_p = ucred_getegid(cred);
		ucred_free(cred);
		if ((int)*uid_p == -1 || (int)*gid_p == -1)
			return -1;
		return 0;
	}
#else
	errno = ENOSYS;
#endif /* HAVE_GETPEERUCRED */
#endif /* !SO_PEERCRED */
	return -1;
}
Beispiel #2
0
/*
 * call-seq:
 *   basicsocket.getpeereid => [euid, egid]
 *
 * Returns the user and group on the peer of the UNIX socket.
 * The result is a two element array which contains the effective uid and the effective gid.
 *
 *   Socket.unix_server_loop("/tmp/sock") {|s|
 *     begin
 *       euid, egid = s.getpeereid
 *
 *       # Check the connected client is myself or not.
 *       next if euid != Process.uid
 *
 *       # do something about my resource.
 *
 *     ensure
 *       s.close
 *     end
 *   }
 *
 */
static VALUE
bsock_getpeereid(VALUE self)
{
UNRUBBY_SOCKET_HACK;
#if defined(HAVE_GETPEEREID)
    rb_io_t *fptr;
    uid_t euid;
    gid_t egid;
    GetOpenFile(self, fptr);
    if (getpeereid(fptr->fd, &euid, &egid) == -1)
	rb_sys_fail("getpeereid");
    return rb_assoc_new(UIDT2NUM(euid), GIDT2NUM(egid));
#elif defined(SO_PEERCRED) /* GNU/Linux */
    rb_io_t *fptr;
    struct ucred cred;
    socklen_t len = sizeof(cred);
    GetOpenFile(self, fptr);
    if (getsockopt(fptr->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
	rb_sys_fail("getsockopt(SO_PEERCRED)");
    return rb_assoc_new(UIDT2NUM(cred.uid), GIDT2NUM(cred.gid));
#elif defined(HAVE_GETPEERUCRED) /* Solaris */
    rb_io_t *fptr;
    ucred_t *uc = NULL;
    VALUE ret;
    GetOpenFile(self, fptr);
    if (getpeerucred(fptr->fd, &uc) == -1)
	rb_sys_fail("getpeerucred");
    ret = rb_assoc_new(UIDT2NUM(ucred_geteuid(uc)), GIDT2NUM(ucred_getegid(uc)));
    ucred_free(uc);
    return ret;
#endif
}
Beispiel #3
0
int
auth_recv (m_msg_t m, uid_t *uid, gid_t *gid)
{
    ucred_t *ucred = NULL;
    uid_t    uid_tmp;
    gid_t    gid_tmp;
    int      rc = -1;

    if (getpeerucred (m->sd, &ucred) < 0) {
        log_msg (LOG_ERR, "Failed to get peer ucred: %s", strerror (errno));
    }
    else if ((uid_tmp = ucred_geteuid (ucred)) < 0) {
        log_msg (LOG_ERR, "Failed to get peer UID: %s", strerror (errno));
    }
    else if ((gid_tmp = ucred_getegid (ucred)) < 0) {
        log_msg (LOG_ERR, "Failed to get peer GID: %s", strerror (errno));
    }
    else {
        *uid = uid_tmp;
        *gid = gid_tmp;
        rc = 0;
    }

    if (ucred) {
        ucred_free (ucred);
    }
    return (rc);
}
Beispiel #4
0
int
get_peer_label(int fd, char **slabel)
{
	if (is_system_labeled()) {
		ucred_t *uc = NULL;
		m_label_t *sl;
		char *pslabel = NULL; /* peer's slabel */

		if ((fd < 0) || (slabel == NULL)) {
			errno = EINVAL;
			return (-1);
		}

		if (getpeerucred(fd, &uc) == -1)
			return (-1);

		sl = ucred_getlabel(uc);
		if (label_to_str(sl, &pslabel, M_INTERNAL, DEF_NAMES) != 0)
			syslog(LOG_WARNING, "label_to_str(): %m");
		ucred_free(uc);

		if (pslabel != NULL) {
			syslog(LOG_DEBUG, "get_peer_label(%d, %s): becomes %s",
				fd, (*slabel ? *slabel : "NULL"), pslabel);
			if (*slabel != NULL)
				free(*slabel);
			*slabel = strdup(pslabel);
		}
	}

	return (0);
}
Beispiel #5
0
/*
 * Set local connection credentials into given hash structure
 */
int
__pmServerSetLocalCreds(int fd, __pmHashCtl *attrs)
{
#if defined(HAVE_STRUCT_UCRED)		/* Linux */
    struct ucred ucred;
    __pmSockLen length = sizeof(ucred);

    if (__pmGetSockOpt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length) < 0)
	return -oserror();
    return SetCredentialAttrs(attrs, ucred.pid, ucred.uid, ucred.gid);

#elif defined(HAVE_GETPEEREID)		/* MacOSX */
    uid_t uid;
    gid_t gid;

    if (getpeereid(__pmFD(fd), &uid, &gid) < 0)
	return -oserror();
    return SetCredentialAttrs(attrs, 0, uid, gid);

#elif defined(HAVE_GETPEERUCRED)	/* Solaris */
    unsigned int uid, gid, pid;
    ucred_t *ucred = NULL;

    if (getpeerucred(__pmFD(fd), &ucred) < 0)
	return -oserror();
    pid = ucred_getpid(ucred);
    uid = ucred_geteuid(ucred);
    gid = ucred_getegid(ucred);
    ucred_free(ucred);
    return SetCredentialAttrs(attrs, pid, uid, gid);

#else
    return -EOPNOTSUPP;
#endif
}
Beispiel #6
0
/**
 * pfl_socket_getpeercred - Retrieve credentials of process on other end
 *	of a UNIX domain socket.
 * @s: socket file descriptor.
 * @uid: value-result user ID.
 * @gid: value-result group ID.
 */
int
pfl_socket_getpeercred(int s, uid_t *uid, gid_t *gid)
{
#ifdef HAVE_GETPEEREID
	if (getpeereid(s, uid, gid) == -1)
		return (errno);
#elif defined(HAVE_GETPEERUCRED)
	ucred_t *ucr;

	if (getpeerucred(s, &ucr) == -1)
		return (errno);
	*uid = ucred_geteuid(ucr);
	*gid = ucred_getegid(ucr);
	ucred_free(ucr);
#else
	struct ucred ucr;
	socklen_t len;

	len = sizeof(ucr);
	if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &ucr, &len))
		return (errno);
	*uid = ucr.uid;
	*gid = ucr.gid;
#endif
	return (0);
}
Beispiel #7
0
int getpeereid(int sock, uid_t *euid, gid_t *egid)
{
    int rc = -1;

#ifdef HAVE_GETPEERUCRED
    ucred_t *cred;

    rc = getpeerucred(sock, &cred);
    if (rc == 0) {
	if (euid) *euid = ucred_geteuid(cred);
	if (egid) *egid = ucred_getegid(cred);
	ucred_free(cred);
    }
#elif 0 // defined(SO_PEERCRED)
    struct ucred cred;
    socklen_t len = sizeof(struct ucred);

    rc = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &len);
    if (rc == 0) {
	if (euid) *euid = cred.uid;
	if (egid) *egid = cred.gid;
    }
#else
//#warning "Need getpeereid(), getpeerucred(), or getsockopt(SO_PEERCRED) support"
    if (euid) *euid = 65534; /* nobody */
    if (egid) *egid = 65534; /* nogroup */
#endif
    return rc;
}
Beispiel #8
0
/* Retrieve the credentials from the peer using the connect file
   descriptor FD.  Returns 0 on success or -1 on error.  */
int
credentials_from_socket (int fd, pid_t *r_pid, uid_t *r_uid, gid_t *r_gid)
{
  int rc = -1;

#ifdef HAVE_SO_PEERCRED
  {
    struct ucred cr;
    socklen_t cl = sizeof cr;

    if (!getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
      {
         *r_pid = cr.pid;
         *r_uid = cr.uid;
         *r_gid = cr.gid;
         rc = 0;
      }
  }
#elif defined (HAVE_GETPEERUCRED)
  {
    ucred_t *ucred = NULL;

    if (getpeerucred (fd, &ucred) != -1)
      {
	*r_pid = ucred_getpid (ucred);
        *r_uid = ucred_geteuid (ucred);
        *r_gid = ucred_getegid (ucred);
        rc = 0;
	ucred_free (ucred);
      }
  }
#elif defined (HAVE_LOCAL_PEEREID)
  {
    struct unpcbid unp;
    socklen_t unpl = sizeof unp;

    if (getsockopt (fd, 0, LOCAL_PEEREID, &unp, &unpl) != -1)
      {
	*r_pid = unp.unp_pid;
	*r_uid = unp.unp_euid;
	*r_gid = unp.unp_egid;
	rc = 0;
      }
  }
#elif defined(HAVE_GETPEEREID)
  {
    if (getpeereid (fd, r_uid, r_gid) != -1)
      {
	r_pid = (pid_t)(-1);
	rc = 0;
      }
  }
#endif

  return rc;
}
Beispiel #9
0
int main (void)
{
  ucred_t *cred ;
  uid_t uid ;
  gid_t gid ;
  int s = 0 ;
  getpeerucred(s, &cred) ;
  uid = ucred_geteuid(cred) ;
  gid = ucred_getegid(cred) ;
  ucred_free(cred) ;
  return 0 ;
}
Beispiel #10
0
int
getpeereid(int s, uid_t *euid, gid_t *gid)
{
	ucred_t *ucred = NULL;

	if (getpeerucred(s, &ucred) == -1)
		return (-1);
	if ((*euid = ucred_geteuid(ucred)) == -1)
		return (-1);
	if ((*gid = ucred_getrgid(ucred)) == -1)
		return (-1);

	ucred_free(ucred);

	return (0);
}
Beispiel #11
0
static int
retrievePeerCredentials (PeerCredentials *credentials, int fd) {
  *credentials = NULL;
  if (getpeerucred(fd, credentials) == -1) {
    logSystemError("getpeerucred");
    return 0;
  }

#ifdef HAVE_GETZONEID
  if (ucred_getzoneid(*credentials) != getzoneid()) {
    ucred_free(*credentials);
    return 0;
  }
#endif /* HAVE_GETZONEID */

  return 1;
}
Beispiel #12
0
int
getpeereid(int s, uid_t *euid, gid_t *egid)
{
	ucred_t *cred = alloca(ucred_size());
	int ret;

	ret = getpeerucred(s, &cred);
	if (ret != 0)
		return ret;

	*euid = ucred_geteuid(cred);
	if (*euid < 0)
		return -1;
	*egid = ucred_getegid(cred);
	if (*egid < 0)
		return -1;

	return 0;
}
Beispiel #13
0
static int ctrls_get_creds_peerucred(int sockfd, uid_t *uid, gid_t *gid) {
  ucred_t *cred = NULL;

  if (getpeerucred(sockfd, &cred) < 0) {
    int xerrno = errno;

    pr_trace_msg(trace_channel, 7, "error obtaining credentials using "
      "getpeerucred(3) on fd %d: %s", sockfd, strerror(xerrno));

    errno = xerrno;
    return -1;
  }

  if (uid)
    *uid = ucred_getruid(cred);

  if (gid)
    *gid = ucred_getrgid(cred);

  ucred_free(cred);
  return 0;
}
Beispiel #14
0
int lutil_getpeereid( int s, uid_t *euid, gid_t *egid
#ifdef LDAP_PF_LOCAL_SENDMSG
	, struct berval *peerbv
#endif
	)
{
#ifdef LDAP_PF_LOCAL
#if defined( HAVE_GETPEERUCRED )
	ucred_t *uc = NULL;
	if( getpeerucred( s, &uc ) == 0 )  {
		*euid = ucred_geteuid( uc );
		*egid = ucred_getegid( uc );
		ucred_free( uc );
		return 0;
	}

#elif defined( SO_PEERCRED )
	struct ucred peercred;
	ber_socklen_t peercredlen = sizeof peercred;

	if(( getsockopt( s, SOL_SOCKET, SO_PEERCRED,
		(void *)&peercred, &peercredlen ) == 0 )
		&& ( peercredlen == sizeof peercred ))
	{
		*euid = peercred.uid;
		*egid = peercred.gid;
		return 0;
	}

#elif defined( LOCAL_PEERCRED )
	struct xucred peercred;
	ber_socklen_t peercredlen = sizeof peercred;

	if(( getsockopt( s, LOCAL_PEERCRED, 1,
		(void *)&peercred, &peercredlen ) == 0 )
		&& ( peercred.cr_version == XUCRED_VERSION ))
	{
		*euid = peercred.cr_uid;
		*egid = peercred.cr_gid;
		return 0;
	}
#elif defined( LDAP_PF_LOCAL_SENDMSG ) && defined( MSG_WAITALL )
	int err, fd;
	struct iovec iov;
	struct msghdr msg = {0};
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
# ifndef CMSG_SPACE
# define CMSG_SPACE(len)	(_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
# endif
# ifndef CMSG_LEN
# define CMSG_LEN(len)		(_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
# endif
	struct {
		struct cmsghdr cm;
		int fd;
	} control_st;
	struct cmsghdr *cmsg;
# endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
	struct stat st;
	struct sockaddr_un lname, rname;
	ber_socklen_t llen, rlen;

	rlen = sizeof(rname);
	llen = sizeof(lname);
	memset( &lname, 0, sizeof( lname ));
	getsockname(s, (struct sockaddr *)&lname, &llen);

	iov.iov_base = peerbv->bv_val;
	iov.iov_len = peerbv->bv_len;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	peerbv->bv_len = 0;

# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
	msg.msg_control = &control_st;
	msg.msg_controllen = sizeof( struct cmsghdr ) + sizeof( int );	/* no padding! */

	cmsg = CMSG_FIRSTHDR( &msg );
# else
	msg.msg_accrights = (char *)&fd;
	msg.msg_accrightslen = sizeof(fd);
# endif

	/*
	 * AIX returns a bogus file descriptor if recvmsg() is
	 * called with MSG_PEEK (is this a bug?). Hence we need
	 * to receive the Abandon PDU.
	 */
	err = recvmsg( s, &msg, MSG_WAITALL );
	if( err >= 0 &&
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
	    cmsg->cmsg_len == CMSG_LEN( sizeof(int) ) &&
	    cmsg->cmsg_level == SOL_SOCKET &&
	    cmsg->cmsg_type == SCM_RIGHTS
# else
		msg.msg_accrightslen == sizeof(int)
# endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL*/
	) {
		int mode = S_IFIFO|S_ISUID|S_IRWXU;

		/* We must receive a valid descriptor, it must be a pipe,
		 * it must only be accessible by its owner, and it must
		 * have the name of our socket written on it.
		 */
		peerbv->bv_len = err;
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
		fd = (*(int *)CMSG_DATA( cmsg ));
# endif
		err = fstat( fd, &st );
		if ( err == 0 )
			rlen = read(fd, &rname, rlen);
		close(fd);
		if( err == 0 && st.st_mode == mode &&
			llen == rlen && !memcmp(&lname, &rname, llen))
		{
			*euid = st.st_uid;
			*egid = st.st_gid;
			return 0;
		}
	}
#elif defined(SOCKCREDSIZE)
	struct msghdr msg;
	ber_socklen_t crmsgsize;
	void *crmsg;
	struct cmsghdr *cmp;
	struct sockcred *sc;

	memset(&msg, 0, sizeof msg);
	crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
	if (crmsgsize == 0) goto sc_err;
	crmsg = malloc(crmsgsize);
	if (crmsg == NULL) goto sc_err;
	memset(crmsg, 0, crmsgsize);
	
	msg.msg_control = crmsg;
	msg.msg_controllen = crmsgsize;
	
	if (recvmsg(s, &msg, 0) < 0) {
		free(crmsg);
		goto sc_err;
	}	

	if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
		free(crmsg);
		goto sc_err;
	}	
	
	cmp = CMSG_FIRSTHDR(&msg);
	if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
		printf("nocreds\n");
		goto sc_err;
	}	
	
	sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
	
	*euid = sc->sc_euid;
	*egid = sc->sc_egid;

	free(crmsg);
	return 0;

sc_err:	
#endif
#endif /* LDAP_PF_LOCAL */

	return -1;
}
Beispiel #15
0
value netsys_get_peer_credentials(value fd) {
    CAMLparam1(fd);
    CAMLlocal1(result);

#if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(HAVE_GETPEERUCRED)
    uid_t uid;
    gid_t gid;
#else
    int uid;
    int gid;
#endif

#if defined(HAVE_GETPEEREID)
    /* BSD, AIX, Cygwin */
    /* http://cr.yp.to/docs/secureipc.html */
    if (getpeereid(Int_val(fd), &uid, &gid) != 0) {
	uerror("getpeereid", Nothing);
    }

#elif defined(SO_PEERCRED)
    /* Linux */
    {
	socklen_t len;
	struct ucred credentials;

	len = sizeof(struct ucred);
	if (getsockopt(Int_val(fd),
		       SOL_SOCKET,
		       SO_PEERCRED,
		       &credentials,
		       &len) == -1) {
	    uerror("getsockopt",Nothing);
	};
	uid = credentials.uid;       /* Effective user ID */
	gid = credentials.gid;       /* Effective group ID */
    }
#elif defined(HAVE_GETPEERUCRED)
    /* Solaris */
    { 
	ucred_t    *ucred;
	ucred = NULL;			/* must be initialized to NULL */
	if (getpeerucred(Int_val(fd), &ucred) == -1) {
	    uerror("getpeerucred",Nothing);
	};
	if ((uid = ucred_geteuid(ucred)) == -1) {
	    uerror("ucred_geteuid",Nothing);
	    ucred_free(ucred);
	};
	if ((gid = ucred_getegid(ucred)) == -1) {
	    uerror("ucred_getegid",Nothing);
	    ucred_free(ucred);
	};
	ucred_free(ucred);
    }
#else
    invalid_argument("get_peer_credentials");
#endif

    /* Allocate a pair, and put the result into it: */
    result = alloc_tuple(2);
    Store_field(result, 0, Val_int(uid));
    Store_field(result, 1, Val_int(gid));

    CAMLreturn(result);
}
int
egg_unix_credentials_read (int sock, pid_t *pid, uid_t *uid)
{
    struct msghdr msg;
    struct iovec iov;
    char buf;
    int ret;

#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
    /* Prefer CMSGCRED over LOCAL_CREDS because the former provides the
     * remote PID. */
#if defined(HAVE_CMSGCRED)
    struct cmsgcred *cred;
#else /* defined(LOCAL_CREDS) */
    struct sockcred *cred;
#endif
    union {
        struct cmsghdr hdr;
        char cred[CMSG_SPACE (sizeof *cred)];
    } cmsg;
#endif

    *pid = 0;
    *uid = 0;

    /* If LOCAL_CREDS are used in this platform, they have already been
     * initialized by init_connection prior to sending of the credentials
     * byte we receive below. */

    iov.iov_base = &buf;
    iov.iov_len = 1;

    memset (&msg, 0, sizeof (msg));
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
    memset (&cmsg, 0, sizeof (cmsg));
    msg.msg_control = (caddr_t) &cmsg;
    msg.msg_controllen = CMSG_SPACE(sizeof *cred);
#endif

again:
    ret = recvmsg (sock, &msg, 0);

    if (ret < 0) {
        if (errno == EINTR)
            goto again;
        return -1;

    } else if (ret == 0) {
        /* Disconnected */
        return -1;
    }

    if (buf != '\0') {
        fprintf (stderr, "credentials byte was not nul\n");
        return -1;
    }

#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
    if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof *cred) ||
            cmsg.hdr.cmsg_type != SCM_CREDS) {
        fprintf (stderr, "message from recvmsg() was not SCM_CREDS\n");
        return -1;
    }
#endif

    {
#ifdef SO_PEERCRED
        struct ucred cr;
        socklen_t cr_len = sizeof (cr);

        if (getsockopt (sock, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
                cr_len == sizeof (cr)) {
            *pid = cr.pid;
            *uid = cr.uid;
        } else {
            fprintf (stderr, "failed to getsockopt() credentials, returned len %d/%d\n",
                     cr_len, (int) sizeof (cr));
            return -1;
        }
#elif defined(HAVE_CMSGCRED)
        cred = (struct cmsgcred *) CMSG_DATA (&cmsg.hdr);
        *pid = cred->cmcred_pid;
        *uid = cred->cmcred_euid;
#elif defined(LOCAL_CREDS)
        cred = (struct sockcred *) CMSG_DATA (&cmsg.hdr);
        *pid = 0;
        *uid = cred->sc_euid;
        set_local_creds(sock, 0);
#elif defined(HAVE_GETPEEREID) /* OpenBSD */
        uid_t euid;
        gid_t egid;
        *pid = 0;

        if (getpeereid (sock, &euid, &egid) == 0) {
            *uid = euid;
        } else {
            fprintf (stderr, "getpeereid() failed: %s\n", strerror (errno));
            return -1;
        }
#elif defined(HAVE_GETPEERUCRED)
        ucred_t *uc = NULL;

        if (getpeerucred (sock, &uc) == 0) {
            *pid = ucred_getpid (uc);
            *uid = ucred_geteuid (uc);
            ucred_free (uc);
        } else {
            fprintf (stderr, "getpeerucred() failed: %s\n", strerror (errno));
            return -1;
        }
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
        fprintf (stderr, "socket credentials not supported on this OS\n");
        return -1;
#endif
    }

    return 0;
}
Beispiel #17
0
static int32_t
qb_ipcs_uc_recv_and_auth(int32_t sock, void *msg, size_t len,
			 struct ipc_auth_ugp *ugp)
{
	int32_t res = 0;
	struct msghdr msg_recv;
	struct iovec iov_recv;

#ifdef SO_PASSCRED
	char cmsg_cred[CMSG_SPACE(sizeof(struct ucred))];
	int off = 0;
	int on = 1;
#endif
	msg_recv.msg_iov = &iov_recv;
	msg_recv.msg_iovlen = 1;
	msg_recv.msg_name = 0;
	msg_recv.msg_namelen = 0;
#ifdef SO_PASSCRED
	msg_recv.msg_control = (void *)cmsg_cred;
	msg_recv.msg_controllen = sizeof(cmsg_cred);
#endif
#ifdef QB_SOLARIS
	msg_recv.msg_accrights = 0;
	msg_recv.msg_accrightslen = 0;
#else
	msg_recv.msg_flags = 0;
#endif /* QB_SOLARIS */

	iov_recv.iov_base = msg;
	iov_recv.iov_len = len;
#ifdef SO_PASSCRED
	setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
#endif

	res = qb_ipc_us_recv_msghdr(sock, &msg_recv, msg, len);
	if (res < 0) {
		goto cleanup_and_return;
	}
	if (res != len) {
		res = -EIO;
		goto cleanup_and_return;
	}

	/*
	 * currently support getpeerucred, getpeereid, and SO_PASSCRED credential
	 * retrieval mechanisms for various Platforms
	 */
#ifdef HAVE_GETPEERUCRED
	/*
	 * Solaris and some BSD systems
	 */
	{
		ucred_t *uc = NULL;

		if (getpeerucred(sock, &uc) == 0) {
			res = 0;
			ugp->uid = ucred_geteuid(uc);
			ugp->gid = ucred_getegid(uc);
			ugp->pid = ucred_getpid(uc);
			ucred_free(uc);
		} else {
			res = -errno;
		}
	}
#elif HAVE_GETPEEREID
	/*
	 * Usually MacOSX systems
	 */
	{
		/*
		 * TODO get the peer's pid.
		 * c->pid = ?;
		 */
		if (getpeereid(sock, &ugp->uid, &ugp->gid) == 0) {
			res = 0;
		} else {
			res = -errno;
		}
	}

#elif SO_PASSCRED
	/*
	 * Usually Linux systems
	 */
	{
		struct ucred cred;
		struct cmsghdr *cmsg;

		res = -EINVAL;
		for (cmsg = CMSG_FIRSTHDR(&msg_recv); cmsg != NULL;
		     cmsg = CMSG_NXTHDR(&msg_recv, cmsg)) {
			if (cmsg->cmsg_type != SCM_CREDENTIALS)
				continue;

			memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct ucred));
			res = 0;
			ugp->pid = cred.pid;
			ugp->uid = cred.uid;
			ugp->gid = cred.gid;
			break;
		}
	}
#else /* no credentials */
	ugp->pid = 0;
	ugp->uid = 0;
	ugp->gid = 0;
	res = -ENOTSUP;
#endif /* no credentials */

cleanup_and_return:

#ifdef SO_PASSCRED
	setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &off, sizeof(off));
#endif

	return res;
}
Beispiel #18
0
static int
lx_getsockopt(ulong_t *args)
{
	int sockfd = (int)args[0];
	int level = (int)args[1];
	int optname = (int)args[2];
	void *optval = (void *)args[3];
	int *optlenp = (int *)args[4];
	int r;

	lx_debug("\tgetsockopt(%d, %d, %d, 0x%p, 0x%p)", sockfd, level, optname,
	    optval, optlenp);

	/*
	 * According to the Linux man page, a NULL optval should indicate
	 * (as in Solaris) that no return value is expected.  Instead, it
	 * actually triggers an EFAULT error.
	 */
	if (optval == NULL)
		return (-EFAULT);

	/*
	 * Do a table lookup of the Solaris equivalent of the given option
	 */
	if (level < IPPROTO_IP || level >= IPPROTO_TAB_SIZE)
		return (-EOPNOTSUPP);

	if (ltos_proto_opts[level].maxentries == 0 ||
	    optname <= 0 || optname >= (ltos_proto_opts[level].maxentries))
		return (-ENOPROTOOPT);

	if (((level == LX_SOL_SOCKET) && (optname == LX_SO_PASSCRED)) ||
	    ((level == IPPROTO_TCP) && (optname == LX_TCP_CORK))) {
		/*
		 * Linux sets LX_SO_PASSCRED when it wants to send credentials
		 * over a socket. Since we do not support it, it is never set
		 * and we return 0.
		 *
		 * We don't support TCP_CORK but some apps rely on it.  So,
		 * rather than return an error we just return 0.  This
		 * isn't exactly a lie, since this option really isn't set,
		 * but it's not the whole truth either.  Fortunately, we
		 * aren't under oath.
		 */
		r = 0;
		if (uucopy(&r, optval, sizeof (int)) != 0)
			return (-errno);
		r = sizeof (int);
		if (uucopy(&r, optlenp, sizeof (int)) != 0)
			return (-errno);
		return (0);
	}
	if ((level == LX_SOL_SOCKET) && (optname == LX_SO_PEERCRED)) {
		struct lx_ucred	lx_ucred;
		ucred_t		*ucp;

		/*
		 * We don't support SO_PEERCRED, but we do have equivalent
		 * functionality in getpeerucred() so invoke that here.
		 */

		/* Verify there's going to be enough room for the results. */
		if (uucopy(optlenp, &r, sizeof (int)) != 0)
			return (-errno);
		if (r < sizeof (struct lx_ucred))
			return (-EOVERFLOW);

		/*
		 * We allocate a ucred_t ourselves rather than allow
		 * getpeerucred() to do it for us because getpeerucred()
		 * uses malloc(3C) and we'd rather use SAFE_ALLOCA().
		 */
		if ((ucp = (ucred_t *)SAFE_ALLOCA(ucred_size())) == NULL)
			return (-ENOMEM);

		/* Get the credential for the remote end of this socket. */
		if (getpeerucred(sockfd, &ucp) != 0)
			return (-errno);
		if (((lx_ucred.lxu_pid = ucred_getpid(ucp)) == -1) ||
		    ((lx_ucred.lxu_uid = ucred_geteuid(ucp)) == (uid_t)-1) ||
		    ((lx_ucred.lxu_gid = ucred_getegid(ucp)) == (gid_t)-1)) {
			return (-errno);
		}

		/* Copy out the results. */
		if ((uucopy(&lx_ucred, optval, sizeof (lx_ucred))) != 0)
			return (-errno);
		r = sizeof (lx_ucred);
		if ((uucopy(&r, optlenp, sizeof (int))) != 0)
			return (-errno);
		return (0);
	}

	optname = ltos_proto_opts[level].proto[optname];

	if (optname == OPTNOTSUP)
		return (-ENOPROTOOPT);

	if (level == LX_SOL_SOCKET)
		level = SOL_SOCKET;

	r = getsockopt(sockfd, level, optname, optval, optlenp);

	return ((r < 0) ? -errno : r);
}
Beispiel #19
0
static int32_t
qb_ipc_auth_creds(struct ipc_auth_data *data)
{
	int32_t res = 0;

	/*
	 * currently support getpeerucred, getpeereid, and SO_PASSCRED credential
	 * retrieval mechanisms for various Platforms
	 */
#ifdef HAVE_GETPEERUCRED
	/*
	 * Solaris and some BSD systems
	 */
	{
		ucred_t *uc = NULL;

		if (getpeerucred(data->sock, &uc) == 0) {
			res = 0;
			data->ugp.uid = ucred_geteuid(uc);
			data->ugp.gid = ucred_getegid(uc);
			data->ugp.pid = ucred_getpid(uc);
			ucred_free(uc);
		} else {
			res = -errno;
		}
	}
#elif defined(HAVE_GETPEEREID)
	/*
	* Usually MacOSX systems
	*/
	{
		/*
		* TODO get the peer's pid.
		* c->pid = ?;
		*/
		if (getpeereid(data->sock, &data->ugp.uid, &data->ugp.gid) == 0) {
			res = 0;
		} else {
			res = -errno;
		}
	}

#elif defined(SO_PASSCRED)
	/*
	* Usually Linux systems
	*/
	{
		struct ucred cred;
		struct cmsghdr *cmsg;

		res = -EINVAL;
		for (cmsg = CMSG_FIRSTHDR(&data->msg_recv); cmsg != NULL;
			cmsg = CMSG_NXTHDR(&data->msg_recv, cmsg)) {
			if (cmsg->cmsg_type != SCM_CREDENTIALS)
				continue;

			memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct ucred));
			res = 0;
			data->ugp.pid = cred.pid;
			data->ugp.uid = cred.uid;
			data->ugp.gid = cred.gid;
			break;
		}
	}
#else /* no credentials */
	data->ugp.pid = 0;
	data->ugp.uid = 0;
	data->ugp.gid = 0;
	res = -ENOTSUP;
#endif /* no credentials */

	return res;
}
Beispiel #20
0
/*
 * Accept a new client request.  A struct ilbd_client_t is allocated to
 * store the client info.  The accepted socket is port_associate() with
 * the given port.  And the allocated ilbd_client_t struct is passed as
 * the user pointer.
 */
static void
new_req(int ev_port, int listener, void *ev_obj)
{
	struct sockaddr	sa;
	int		sa_len;
	int		new_sd;
	int		sflags;
	ilbd_client_t	*cli;
	int		res;
	uid_t		uid;

	sa_len = sizeof (sa);
	if ((new_sd = accept(listener, &sa, &sa_len)) == -1) {
		/* don't log if we're out of file descriptors */
		if (errno != EINTR && errno != EMFILE)
			logperror("new_req: accept failed");
		goto done;
	}

	/* Set the new socket to be non-blocking. */
	if ((sflags = fcntl(new_sd, F_GETFL, 0)) == -1) {
		logperror("new_req: fcntl(F_GETFL)");
		goto clean_up;
	}
	if (fcntl(new_sd, F_SETFL, sflags | O_NONBLOCK) == -1) {
		logperror("new_req: fcntl(F_SETFL)");
		goto clean_up;
	}
	if (fcntl(new_sd, F_SETFD, FD_CLOEXEC) == -1) {
		logperror("new_req: fcntl(FD_CLOEXEC)");
		goto clean_up;
	}
	if ((cli = calloc(1, sizeof (ilbd_client_t))) == NULL) {
		logerr("new_req: malloc(ilbd_client_t)");
		goto clean_up;
	}
	res = getpeerucred(new_sd, &cli->cli_peer_ucredp);
	if (res == -1) {
		logperror("new_req: getpeerucred failed");
		goto clean_up;
	}
	if ((uid = ucred_getruid(cli->cli_peer_ucredp)) == (uid_t)-1) {
		logperror("new_req: ucred_getruid failed");
		goto clean_up;
	}
	cli->cli_pw_bufsz = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX);
	if ((cli->cli_pw_buf = malloc(cli->cli_pw_bufsz)) == NULL) {
		free(cli);
		logerr("new_req: malloc(cli_pw_buf)");
		goto clean_up;
	}
	if (getpwuid_r(uid, &cli->cli_pw, cli->cli_pw_buf,
	    cli->cli_pw_bufsz) == NULL) {
		free(cli->cli_pw_buf);
		free(cli);
		logperror("new_req: invalid user");
		goto clean_up;
	}
	cli->cli_ev = ILBD_EVENT_REQ;
	cli->cli_sd = new_sd;
	cli->cli_cmd = ILBD_BAD_CMD;
	cli->cli_saved_reply = NULL;
	cli->cli_saved_size = 0;
	if (port_associate(ev_port, PORT_SOURCE_FD, new_sd, POLLRDNORM,
	    cli) == -1) {
		logperror("new_req: port_associate(cli) failed");
		free(cli->cli_pw_buf);
		free(cli);
clean_up:
		(void) close(new_sd);
	}

done:
	/* Re-associate the listener with the event port. */
	if (port_associate(ev_port, PORT_SOURCE_FD, listener, POLLRDNORM,
	    ev_obj) == -1) {
		logperror("new_req: port_associate(listener) failed");
		exit(1);
	}
}
Beispiel #21
0
static pmix_status_t validate_cred(pmix_peer_t *peer, char *cred)
{
#if defined(SO_PEERCRED)
#ifdef HAVE_STRUCT_SOCKPEERCRED_UID
#define HAVE_STRUCT_UCRED_UID
    struct sockpeercred ucred;
#else
    struct ucred ucred;
#endif
    socklen_t crlen = sizeof (ucred);
#endif
#ifdef HAVE_GETPEERUCRED
    ucred_t *ucred = NULL;
#endif
    uid_t euid;
    gid_t gid;

    pmix_output_verbose(2, pmix_globals.debug_output,
                        "sec: native validate_cred %s", cred ? cred : "NULL");

#if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
    /* Ignore received 'cred' and validate ucred for socket instead. */
    pmix_output_verbose(2, pmix_globals.debug_output,
                        "sec:native checking getsockopt for peer credentials");
    if (getsockopt (peer->sd, SOL_SOCKET, SO_PEERCRED, &ucred, &crlen) < 0) {
        pmix_output_verbose(2, pmix_globals.debug_output,
                            "sec: getsockopt SO_PEERCRED failed: %s",
                            strerror (pmix_socket_errno));
        return PMIX_ERR_INVALID_CRED;
    }
#if defined(HAVE_STRUCT_UCRED_UID)
    euid = ucred.uid;
    gid = ucred.gid;
#else
    euid = ucred.cr_uid;
    gid = ucred.cr_gid;
#endif

#elif defined(HAVE_GETPEEREID)
    pmix_output_verbose(2, pmix_globals.debug_output,
                        "sec:native checking getpeereid for peer credentials");
    if (0 != getpeereid(peer->sd, &euid, &gid)) {
        pmix_output_verbose(2, pmix_globals.debug_output,
                            "sec: getsockopt getpeereid failed: %s",
                            strerror (pmix_socket_errno));
        return PMIX_ERR_INVALID_CRED;
    }
#elif defined(HAVE_GETPEERUCRED)
    pmix_output_verbose(2, pmix_globals.debug_output,
                        "sec:native checking getpeerucred for peer credentials");
    if (0 != getpeerucred(peer->sd, &ucred)) {
        pmix_output_verbose(2, pmix_globals.debug_output,
                            "sec: getsockopt getpeerucred failed: %s",
                            strerror (pmix_socket_errno));
        pmix_output_verbose(2, pmix_globals.debug_output,
                            "sec: getsockopt getpeerucred failed: %s",
                            strerror (errno));
        return PMIX_ERR_INVALID_CRED;
    }
    euid = ucred_geteuid(ucred);
    gid = ucred_getrgid(ucred);
    ucred_free(ucred);
#else
    pmix_output_verbose(2, pmix_globals.debug_output,
                        "sec: native cannot validate_cred on this system");
    return PMIX_ERR_NOT_SUPPORTED;
#endif

    /* check uid */
    if (euid != peer->info->uid) {
        pmix_output_verbose(2, pmix_globals.debug_output,
                            "sec: socket cred contains invalid uid %u", euid);
        return PMIX_ERR_INVALID_CRED;
    }

    /* check gid */
    if (gid != peer->info->gid) {
        pmix_output_verbose(2, pmix_globals.debug_output,
                            "sec: socket cred contains invalid gid %u", gid);
        return PMIX_ERR_INVALID_CRED;
    }

    pmix_output_verbose(2, pmix_globals.debug_output,
                        "sec: native credential %u:%u valid",
                        euid, gid);
    return PMIX_SUCCESS;
}
Beispiel #22
0
/*
 * Get uid, gid and pid of unix socket peer.
 *
 * Pid may not be availalbe on some OSes.
 * It's set to 0 then.
 */
int getpeercreds(int fd, uid_t *uid_p, gid_t *gid_p, pid_t *pid_p)
{
	/* What a mess */

#if defined(SO_PEERCRED)
	/* linux and others */
#if defined(HAVE_SYS_UCRED_H)
	struct sockpeercred cred;	/* openbsd */
#else
	struct ucred cred;		/* linux */
#endif
	socklen_t len = sizeof(cred);
	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == 0) {
		*uid_p = cred.uid;
		*gid_p = cred.gid;
		*pid_p = cred.pid;
		return 0;
	}
	return -1;
#elif defined(HAVE_GETPEERUCRED)
	/* solaris */
	ucred_t *cred = NULL;
	if (getpeerucred(fd, &cred) == 0) {
		*uid_p = ucred_geteuid(cred);
		*gid_p = ucred_getegid(cred);
		*pid_p = ucred_getpid(cred);
		ucred_free(cred);
		if ((int)*uid_p == -1 || (int)*gid_p == -1)
			return -1;
		return 0;
	}
	return -1;
#elif defined(LOCAL_PEEREID)
	/* netbsd */
	struct unpcbid cred;
	socklen_t len = sizeof(cred);
	if (getsockopt(fd, 0, LOCAL_PEEREID, &cred, &len) != 0)
		return -1;
	*uid_p = cred.unp_euid;
	*gid_p = cred.unp_egid;
	*pid_p = cred.unp_pid;
	return 0;
#elif defined(HAVE_GETPEEREID)
	/* generic bsd; no pid */
	*pid_p = 0;
	return getpeereid(fd, uid_p, gid_p) == 0 ? 0 : -1;
#elif defined(LOCAL_PEERCRED)
	/* freebsd, osx, dfly; no pid */
	struct xucred cred;
	socklen_t len = sizeof(cred);
	if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) != 0)
		return -1;
	if (cred.cr_version != XUCRED_VERSION) {
		errno = EINVAL;
		return -1;
	}
	*uid_p = cred.cr_uid;
	*gid_p = cred.cr_gid;
	*pid_p = 0;
	return 0;
#else
	/* no implementation */
	errno = ENOSYS;
	return -1;
#endif
}
Beispiel #23
0
void *jalls_handler(void *thread_ctx_p) {
	if (!thread_ctx_p) {
		return NULL; //should never happen.
	}

	struct jalls_thread_context *thread_ctx = NULL;
	thread_ctx = thread_ctx_p;
	pid_t *pid = NULL;
	uid_t *uid = NULL;
	int debug = thread_ctx->ctx->debug;
	int err = pthread_detach(pthread_self());
	if (err < 0) {
		if (debug) {
			fprintf(stderr, "Failed to detach the thread\n");
		}
		goto out;
	}

	while (!should_exit) {

		// read protocol version, message type, data length,
		// metadata length and possible fd.
		uint16_t protocol_version;
		uint16_t message_type;
		uint64_t data_len;
		uint64_t meta_len;
		int msg_fd = -1;

		struct msghdr msgh;
		memset(&msgh, 0, sizeof(msgh));

		struct iovec iov[4];
		iov[0].iov_base = &protocol_version;
		iov[0].iov_len = sizeof(protocol_version);
		iov[1].iov_base = &message_type;
		iov[1].iov_len = sizeof(message_type);
		iov[2].iov_base = &data_len;
		iov[2].iov_len = sizeof(data_len);
		iov[3].iov_base = &meta_len;
		iov[3].iov_len = sizeof(meta_len);

		msgh.msg_iov = iov;
		msgh.msg_iovlen = 4;

		char msg_control_buffer[CMSG_SPACE(sizeof(msg_fd))];

		msgh.msg_control = msg_control_buffer;
		msgh.msg_controllen = sizeof(msg_control_buffer);

#ifdef SO_PEERCRED
		struct ucred cred;
		memset(&cred, 0, sizeof(cred));
		pid = &cred.pid;
		uid = &cred.uid;
		*pid = -1;
		*uid = 0;
		socklen_t cred_len = sizeof(cred);
		if (-1 == getsockopt(thread_ctx->fd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len)) {
			if (debug) {
				fprintf(stderr, "failed receiving peer crendentials\n");
			}
		}
#endif
#ifdef SCM_UCRED
		ucred_t *cred = NULL;
		pid_t tmp_pid = -1;
		uid_t tmp_uid = 0;
		pid = &tmp_pid;
		uid = &tmp_uid;
		if (-1 == getpeerucred(thread_ctx->fd, &cred)) {
			if (debug) {
				fprintf(stderr, "failed receiving peer credentials\n");
			}
		} else {
			tmp_pid = ucred_getpid(cred);
			tmp_uid = ucred_geteuid(cred);
			ucred_free(cred);
		}
#endif
		
		ssize_t bytes_recv = jalls_recvmsg_helper(thread_ctx->fd, &msgh, debug);
		if (bytes_recv < 0) {
			if (debug) {
				fprintf(stderr, "Failed to receive the message header\n");
			}
			goto out;
		}
		if (bytes_recv == 0) {
			if (debug) {
				fprintf(stderr, "The peer has shutdown\n");
			}
			goto out;
		}

		//receive fd
		struct cmsghdr *cmsg;
		cmsg = CMSG_FIRSTHDR(&msgh);
		while (cmsg != NULL) {
			if (cmsg->cmsg_level == SOL_SOCKET) {
				if (cmsg->cmsg_type == SCM_RIGHTS && cmsg->cmsg_len == CMSG_LEN(sizeof(msg_fd))) {
					if (message_type != JALLS_JOURNAL_FD_MSG) {
						if (debug) {
							fprintf(stderr, "received an fd for a message type that was not journal_fd\n");
						}
						goto out;
					}
					void *tmp_fd = CMSG_DATA(cmsg);
					if (debug && msg_fd != -1) {
						fprintf(stderr, "received duplicate ancillary data: overwrote the fd\n");
					}
					msg_fd = *((int *)tmp_fd);
					if (msg_fd < 0) {
						if (debug) {
							fprintf(stderr, "received an fd < 0\n");
						}
						goto out;
					}
				} else {
					if (debug) {
						fprintf(stderr, "received unrecognized ancillary data\n");
					}
					goto out;
				}
			}
			cmsg = CMSG_NXTHDR(&msgh, cmsg);
		}

		thread_ctx->peer_pid = *pid;
		thread_ctx->peer_uid = *uid;
		if (debug && *pid == -1) {
			thread_ctx->peer_pid = 0;
			thread_ctx->peer_uid = 0;

			fprintf(stderr, "Did not receive credentials\n");
		}

		if (protocol_version != 1) {
			if (debug) {
				fprintf(stderr, "received protocol version != 1\n");
			}
			return NULL;
		}

		//call appropriate handler
		switch (message_type) {
			case JALLS_LOG_MSG:
				err = jalls_handle_log(thread_ctx, data_len, meta_len);
				break;
			case JALLS_AUDIT_MSG:
				err = jalls_handle_audit(thread_ctx, data_len, meta_len);
				break;
			case JALLS_JOURNAL_MSG:
				err = jalls_handle_journal(thread_ctx, data_len, meta_len);
				break;
			case JALLS_JOURNAL_FD_MSG:
				if (msg_fd < 0) {
					if (debug) {
						fprintf(stderr, "Message type is journal_fd, but no fd was received\n");
					}
					goto out;
				}
				err = jalls_handle_journal_fd(thread_ctx, data_len, meta_len, msg_fd);
				break;
			default:
				if (debug) {
					fprintf(stderr, "Message type is not legal.\n");
				}
				goto out;
		}
		if (err < 0) {
			goto out;
		}
	}

out:
	close(thread_ctx->fd);
	free(thread_ctx);
	return NULL;
}
Beispiel #24
0
/**
 * Create a connection handle by accepting on a listen socket.  This
 * function may block if the listen socket has no connection ready.
 *
 * @param access function to use to check if access is allowed
 * @param access_cls closure for access
 * @param lsock listen socket
 * @return the connection handle, NULL on error
 */
struct GNUNET_CONNECTION_Handle *
GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
                                      void *access_cls,
                                      struct GNUNET_NETWORK_Handle *lsock)
{
  struct GNUNET_CONNECTION_Handle *connection;
  char addr[128];
  socklen_t addrlen;
  struct GNUNET_NETWORK_Handle *sock;
  int aret;
  struct sockaddr_in *v4;
  struct sockaddr_in6 *v6;
  struct sockaddr *sa;
  void *uaddr;
  struct GNUNET_CONNECTION_Credentials *gcp;
  struct GNUNET_CONNECTION_Credentials gc;
#ifdef SO_PEERCRED
  struct ucred uc;
  socklen_t olen;
#endif

  addrlen = sizeof (addr);
  sock =
      GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen);
  if (NULL == sock)
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
    return NULL;
  }
  if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
  {
    GNUNET_break (0);
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
    return NULL;
  }

  sa = (struct sockaddr *) addr;
  v6 = (struct sockaddr_in6 *) addr;
  if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)))
  {
    /* convert to V4 address */
    v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
    memset (v4, 0, sizeof (struct sockaddr_in));
    v4->sin_family = AF_INET;
#if HAVE_SOCKADDR_IN_SIN_LEN
    v4->sin_len = (u_char) sizeof (struct sockaddr_in);
#endif
    memcpy (&v4->sin_addr,
            &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
                                       sizeof (struct in_addr)],
            sizeof (struct in_addr));
    v4->sin_port = v6->sin6_port;
    uaddr = v4;
    addrlen = sizeof (struct sockaddr_in);
  }
  else
  {
    uaddr = GNUNET_malloc (addrlen);
    memcpy (uaddr, addr, addrlen);
  }
  gcp = NULL;
  gc.uid = 0;
  gc.gid = 0;
  if (AF_UNIX == sa->sa_family)
  {
#if HAVE_GETPEEREID
    /* most BSDs */
    if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), &gc.uid, &gc.gid))
      gcp = &gc;
#else
#ifdef SO_PEERCRED
    /* largely traditional GNU/Linux */
    olen = sizeof (uc);
    if ((0 ==
         getsockopt (GNUNET_NETWORK_get_fd (sock), SOL_SOCKET, SO_PEERCRED, &uc,
                     &olen)) && (olen == sizeof (uc)))
    {
      gc.uid = uc.uid;
      gc.gid = uc.gid;
      gcp = &gc;
    }
#else
#if HAVE_GETPEERUCRED
    /* this is for Solaris 10 */
    ucred_t *uc;

    uc = NULL;
    if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
    {
      gc.uid = ucred_geteuid (uc);
      gc.gid = ucred_getegid (uc);
      gcp = &gc;
    }
    ucred_free (uc);
#endif
#endif
#endif
  }

  if ((NULL != access) &&
      (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen))))
  {
    if (GNUNET_NO == aret)
      LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"),
           GNUNET_a2s (uaddr, addrlen));
    GNUNET_break (GNUNET_OK ==
                  GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR));
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
    GNUNET_free (uaddr);
    return NULL;
  }
  connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
  connection->addr = uaddr;
  connection->addrlen = addrlen;
  connection->sock = sock;
  LOG (GNUNET_ERROR_TYPE_INFO, 
       _("Accepting connection from `%s': %p\n"),
       GNUNET_a2s (uaddr, addrlen), connection);
  return connection;
}
Beispiel #25
0
static int
lx_getsockopt(ulong_t *args)
{
	int sockfd = (int)args[0];
	int level = (int)args[1];
	int optname = (int)args[2];
	void *optval = (void *)args[3];
	int *optlenp = (int *)args[4];
	int r;
	int orig_optname;
	lx_proto_opts_t *proto_opts;

	lx_debug("\tgetsockopt(%d, %d, %d, 0x%p, 0x%p)", sockfd, level, optname,
	    optval, optlenp);

	/*
	 * According to the Linux man page, a NULL optval should indicate
	 * (as in Solaris) that no return value is expected.  Instead, it
	 * actually triggers an EFAULT error.
	 */
	if (optval == NULL)
		return (-EFAULT);

	if (level > LX_IPPROTO_RAW || level == LX_IPPROTO_UDP)
		return (-EOPNOTSUPP);

	if ((proto_opts = get_proto_opt_tbl(level)) == NULL)
		return (-ENOPROTOOPT);

	if (optname <= 0 || optname >= (proto_opts->maxentries)) {
		lx_unsupported("Unsupported sockopt %d, proto %d", optname,
		    level);
		return (-ENOPROTOOPT);
	}

	if ((level == LX_IPPROTO_TCP) && (optname == LX_TCP_CORK)) {
		/*
		 * We don't support TCP_CORK but some apps rely on it.  So,
		 * rather than return an error we just return 0.  This
		 * isn't exactly a lie, since this option really isn't set,
		 * but it's not the whole truth either.  Fortunately, we
		 * aren't under oath.
		 */
		r = 0;
		if (uucopy(&r, optval, sizeof (int)) != 0)
			return (-errno);
		r = sizeof (int);
		if (uucopy(&r, optlenp, sizeof (int)) != 0)
			return (-errno);
		return (0);
	}
	if ((level == LX_SOL_SOCKET) && (optname == LX_SO_PEERCRED)) {
		struct lx_ucred	lx_ucred;
		ucred_t		*ucp;

		/*
		 * We don't support SO_PEERCRED, but we do have equivalent
		 * functionality in getpeerucred() so invoke that here.
		 */

		/* Verify there's going to be enough room for the results. */
		if (uucopy(optlenp, &r, sizeof (int)) != 0)
			return (-errno);
		if (r < sizeof (struct lx_ucred))
			return (-EOVERFLOW);

		/*
		 * We allocate a ucred_t ourselves rather than allow
		 * getpeerucred() to do it for us because getpeerucred()
		 * uses malloc(3C) and we'd rather use SAFE_ALLOCA().
		 */
		if ((ucp = (ucred_t *)SAFE_ALLOCA(ucred_size())) == NULL)
			return (-ENOMEM);

		/* Get the credential for the remote end of this socket. */
		if (getpeerucred(sockfd, &ucp) != 0)
			return (-errno);
		if (((lx_ucred.lxu_pid = ucred_getpid(ucp)) == -1) ||
		    ((lx_ucred.lxu_uid = ucred_geteuid(ucp)) == (uid_t)-1) ||
		    ((lx_ucred.lxu_gid = ucred_getegid(ucp)) == (gid_t)-1)) {
			return (-errno);
		}

		/* Copy out the results. */
		if ((uucopy(&lx_ucred, optval, sizeof (lx_ucred))) != 0)
			return (-errno);
		r = sizeof (lx_ucred);
		if ((uucopy(&r, optlenp, sizeof (int))) != 0)
			return (-errno);
		return (0);
	}

	orig_optname = optname;

	optname = proto_opts->proto[optname];
	if (optname == OPTNOTSUP) {
		lx_unsupported("unsupported sockopt %d, proto %d",
		    orig_optname, level);
		return (-ENOPROTOOPT);
	}

	if (level == LX_SOL_SOCKET)
		level = SOL_SOCKET;

	r = getsockopt(sockfd, level, optname, optval, optlenp);

	if (r == 0 && level == SOL_SOCKET && optname == SO_TYPE) {
		/* translate our type back to Linux */
		*(int *)optval = stol_socktype[(*(int *)optval)];
	}

	return ((r < 0) ? -errno : r);
}
Beispiel #26
0
static cs_error_t
req_setup_recv (
	struct conn_info *conn_info)
{
	int res;
	struct msghdr msg_recv;
	struct iovec iov_recv;
	cs_error_t auth_res = CS_ERR_LIBRARY;

#ifdef COROSYNC_LINUX
	struct cmsghdr *cmsg;
	char cmsg_cred[CMSG_SPACE (sizeof (struct ucred))];
	int off = 0;
	int on = 1;
	struct ucred *cred;
#endif
	msg_recv.msg_flags = 0;
	msg_recv.msg_iov = &iov_recv;
	msg_recv.msg_iovlen = 1;
	msg_recv.msg_name = 0;
	msg_recv.msg_namelen = 0;
#ifdef COROSYNC_LINUX
	msg_recv.msg_control = (void *)cmsg_cred;
	msg_recv.msg_controllen = sizeof (cmsg_cred);
#endif
#ifdef COROSYNC_SOLARIS
	msg_recv.msg_accrights = 0;
	msg_recv.msg_accrightslen = 0;
#endif /* COROSYNC_SOLARIS */

	iov_recv.iov_base = &conn_info->setup_msg[conn_info->setup_bytes_read];
	iov_recv.iov_len = sizeof (mar_req_setup_t) - conn_info->setup_bytes_read;
#ifdef COROSYNC_LINUX
	setsockopt(conn_info->fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on));
#endif

retry_recv:
	res = recvmsg (conn_info->fd, &msg_recv, MSG_NOSIGNAL);
	if (res == -1 && errno == EINTR) {
		api->stats_increment_value (conn_info->stats_handle, "recv_retry_count");
		goto retry_recv;
	} else
	if (res == -1 && errno != EAGAIN) {
		return (CS_ERR_LIBRARY);
	} else
	if (res == 0) {
#if defined(COROSYNC_SOLARIS) || defined(COROSYNC_BSD) || defined(COROSYNC_DARWIN)
		/* On many OS poll never return POLLHUP or POLLERR.
		 * EOF is detected when recvmsg return 0.
		 */
		ipc_disconnect (conn_info);
		return (CS_ERR_LIBRARY);
#else
		return (CS_ERR_SECURITY);
#endif
	}
	conn_info->setup_bytes_read += res;

/*
 * currently support getpeerucred, getpeereid, and SO_PASSCRED credential
 * retrieval mechanisms for various Platforms
 */
#ifdef HAVE_GETPEERUCRED
/*
 * Solaris and some BSD systems
 */
	{
		ucred_t *uc = NULL;
		uid_t euid = -1;
		gid_t egid = -1;

		if (getpeerucred (conn_info->fd, &uc) == 0) {
			euid = ucred_geteuid (uc);
			egid = ucred_getegid (uc);
			conn_info->client_pid = ucred_getpid (uc);
			if (api->security_valid (euid, egid)) {
				auth_res = CS_OK;
			} else {
				auth_res = hdb_error_to_cs(errno);
			}
			ucred_free(uc);
		}
	}
#elif HAVE_GETPEEREID
/*
 * Usually MacOSX systems
 */

	{
		uid_t euid;
		gid_t egid;

		/*
		 * TODO get the peer's pid.
		 * conn_info->client_pid = ?;
		 */
		euid = -1;
		egid = -1;
		if (getpeereid (conn_info->fd, &euid, &egid) == 0) {
			if (api->security_valid (euid, egid)) {
				auth_res = CS_OK;
			} else {
				auth_res = hdb_error_to_cs(errno);
			}
		}
	}

#elif SO_PASSCRED
/*
 * Usually Linux systems
 */
	cmsg = CMSG_FIRSTHDR (&msg_recv);
	assert (cmsg);
	cred = (struct ucred *)CMSG_DATA (cmsg);
	if (cred) {
		conn_info->client_pid = cred->pid;
		if (api->security_valid (cred->uid, cred->gid)) {
			auth_res = CS_OK;
		} else {
			auth_res = hdb_error_to_cs(errno);
		}
	}

#else /* no credentials */
	auth_res = CS_OK;
	log_printf (LOGSYS_LEVEL_ERROR, "Platform does not support IPC authentication.  Using no authentication\n");
#endif /* no credentials */

	if (auth_res != CS_OK) {
		ipc_disconnect (conn_info);
		if (auth_res == CS_ERR_NO_RESOURCES) {
			log_printf (LOGSYS_LEVEL_ERROR,
				"Not enough file desciptors for IPC connection.\n");
		} else {
			log_printf (LOGSYS_LEVEL_ERROR, "Invalid IPC credentials.\n");
		}
		return auth_res;
	}

	if (conn_info->setup_bytes_read == sizeof (mar_req_setup_t)) {
#ifdef COROSYNC_LINUX
		setsockopt(conn_info->fd, SOL_SOCKET, SO_PASSCRED,
			&off, sizeof (off));
#endif
		return (CS_OK);
	}
	return (CS_ERR_LIBRARY);
}