Beispiel #1
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 #2
0
static void
N2N_check_priv(
	void			*buf,
	char			*dc_str)
{
	nss_pheader_t		*phdr = (nss_pheader_t *)buf;
	ucred_t			*uc = NULL;
	const priv_set_t	*eset;
	zoneid_t		zoneid;
	int			errnum;
	char			*me = "N2N_check_priv";

	if (door_ucred(&uc) != 0) {
		errnum = errno;
		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
		(me, "door_ucred: %s\n", strerror(errno));

		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum);
	}

	eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
	zoneid = ucred_getzoneid(uc);

	if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) ||
	    eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) :
	    ucred_geteuid(uc) != 0) {

		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
		(me, "%s call failed(cred): caller pid %d, uid %d, "
		    "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
		    ucred_getruid(uc), ucred_geteuid(uc), zoneid);
		ucred_free(uc);

		NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES);
	}

	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
	(me, "nscd received %s cmd from pid %d, uid %d, "
	    "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
	    ucred_getruid(uc), ucred_geteuid(uc), zoneid);

	ucred_free(uc);

	NSCD_RETURN_STATUS_SUCCESS(phdr);
}
Beispiel #3
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 #4
0
void
_nscd_APP_check_cred(
	void		*buf,
	pid_t		*pidp,
	char		*dc_str,
	int		log_comp,
	int		log_level)
{
	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
	ucred_t		*uc = NULL;
	uid_t		ruid;
	uid_t		euid;
	pid_t		pid;
	int		errnum;
	char		*me = "_nscd_APP_check_cred";

	if (door_ucred(&uc) != 0) {
		errnum = errno;
		_NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR)
		(me, "door_ucred: %s\n", strerror(errno));

		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum);
	}

	NSCD_SET_STATUS_SUCCESS(phdr);
	pid = ucred_getpid(uc);
	if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc),
	    euid = ucred_geteuid(uc))) {
		if (pidp != NULL) {
			if (*pidp == (pid_t)-1)
				*pidp = pid;
			else if (*pidp != pid) {
				NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
			}
		}
	} else {
		NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
	}

	ucred_free(uc);

	if (NSCD_STATUS_IS_NOT_OK(phdr)) {
		_NSCD_LOG(log_comp, log_level)
		(me, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
		    "euid %d, header ruid %d, header euid %d\n", dc_str,
		    pid, (pidp != NULL) ? *pidp : -1, ruid, euid,
		    ((nss_pheader_t *)(buf))->p_ruid,
		    ((nss_pheader_t *)(buf))->p_euid);
	}
}
Beispiel #5
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 #6
0
/*ARGSUSED*/
static void
pkg_door_srv(void *cookie, char *argp, size_t asz, door_desc_t *dp,
    uint_t ndesc)
{
	char *p = NULL;
	pkgcmd_t *pcmd = (pkgcmd_t *)argp;
	ucred_t *uc = NULL;
	uid_t caller;
	pid_t pcaller;
	door_desc_t ddp;
	int dnum = 0;
	int one = 1;
	int len = -1;

	if (asz < sizeof (pkgcmd_t)) {
		(void) door_return(NULL, 0, NULL, 0);
		return;
	}

	if (door_ucred(&uc) != 0) {
		(void) door_return(NULL, 0, NULL, 0);
		return;
	}

	caller = ucred_geteuid(uc);
	pcaller = ucred_getpid(uc);
	ucred_free(uc);

	if (caller != myuid) {
		(void) door_return(NULL, 0, NULL, 0);
		return;
	}

	(void) mutex_lock(&mtx);
	ncalls++;

	if (pcaller != client_pid && pcaller != -1 &&
	    (client_pid == 1 || kill(client_pid, 0) != 0)) {
		client_pid = pcaller;
	}

	if (PKG_WRITE_COMMAND(pcmd->cmd))
		while (write_locked > 0)
			(void) cond_wait(&cv, &mtx);

	switch (pcmd->cmd) {
	case PKG_FINDFILE:
		p = file_find((pkgfilter_t *)argp, &len);
		break;
	case PKG_DUMP:
		if (read_only)
			goto err;
		if (logcount > 0)
			pkgdump();
		break;
	case PKG_EXIT:
		if (logcount > 0)
			pkgdump();
		exit(0);
		/*NOTREACHED*/
	case PKG_PKGSYNC:
		if (read_only || logflush() != 0)
			goto err;
		break;
	case PKG_FILTER:
		if (pkgfilter((pkgfilter_t *)argp, &ddp) == 0)
			dnum = 1;
		break;
	case PKG_ADDLINES:
		if (read_only)
			goto err;
		changes++;

		if (pkgaddlines((pkgfilter_t *)argp) != 0)
			goto err;
		/* If we've updated the database, tell the dump thread */
		lastchange = gethrtime();
		(void) cond_broadcast(&cv);
		break;
	case PKG_NOP:
		/* Do nothing but register the current client's pid. */
		break;
	default:
		goto err;
	}

	lastcall = gethrtime();
	(void) mutex_unlock(&mtx);
	(void) door_return(p, len != -1 ? len : p == NULL ? 0 : strlen(p) + 1,
	    dnum == 0 ? NULL : &ddp, dnum);
	return;

err:
	(void) mutex_unlock(&mtx);
	(void) door_return((void *)&one, 4, NULL, NULL);
}
Beispiel #7
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 #8
0
void
_nscd_proc_iamhere(
	void		*buf,
	door_desc_t	*dp,
	uint_t		n_desc,
	int		iam)
{
	int		cslot;
	child_t		*ch;
	int		errnum;
	ucred_t		*uc = NULL;
	uid_t		uid;
	nscd_imhere_t	*ih;
	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
	char		*me = "_nscd_proc_iamhere";


	_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
	(me, "%d receives iamhere from %d\n", _whoami, iam);

	if (door_ucred(&uc) != 0) {
		errnum = errno;
		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
		(me, "door_ucred failed: %s\n", strerror(errnum));

		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
		    NSCD_DOOR_UCRED_ERROR);
	}
	uid = ucred_geteuid(uc);

	switch (iam) {

	case NSCD_MAIN:
		if (_whoami == NSCD_MAIN || uid != main_uid) {
			/*
			 * I'm main, or uid from door is not correct,
			 * this must be an imposter
			 */
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "MAIN IMPOSTER CAUGHT!\n");


			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_MAIN_IMPOSTER);
		}
		break;

	case NSCD_FORKER:
		if (_whoami == NSCD_FORKER || uid != forker_uid) {
			/*
			 * I'm forker, or uid from door is not correct,
			 * this must be an imposter
			 */
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "FORKER IMPOSTER CAUGHT!\n");


			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_FORKER_IMPOSTER);
			break;
		}

		/* only main needs to know the forker */
		if (_whoami != NSCD_MAIN) {

			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_WRONG_NSCD);
			break;
		}

		if (ucred_getpid(uc) != forker_pid) {
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n",
			    ucred_getpid(uc), forker_pid);


			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_FORKER_IMPOSTER);
			break;
		}

		if (n_desc < 1) {
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "BAD FORKER, NO DOOR!\n");


			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_NO_DOOR);
			break;
		}

		if ((dp->d_attributes & DOOR_DESCRIPTOR) &&
		    dp->d_data.d_desc.d_descriptor > 0 &&
		    dp->d_data.d_desc.d_id != 0) {
			(void) mutex_lock(&forking_lock);
			if (forking_door != -1)
				(void) close(forking_door);
			forking_door = dp->d_data.d_desc.d_descriptor;
			(void) mutex_unlock(&forking_lock);

			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "forking door is %d\n", forking_door);

			NSCD_SET_STATUS_SUCCESS(phdr);
		} else {
			NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
			break;
		}

		/* monitor the forker nscd */
		(void) thr_create(NULL, 0, forker_monitor, NULL,
		    THR_DETACHED, NULL);

		break;

	case NSCD_CHILD:
		if (_whoami != NSCD_MAIN) {
			/* child nscd can only talk to the main nscd */
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "CHILD IMPOSTER CAUGHT!\n");

			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_CHILD_IMPOSTER);
			break;
		}

		/* get the main nscd assigned slot number */
		ih = NSCD_N2N_DOOR_DATA(nscd_imhere_t, buf);
		cslot = ih->slot;
		(void) mutex_lock(&child_lock);
		if (cslot < 0 || cslot >= max_pu_nscd)
			ch = NULL;
		else
			ch = child[cslot];
		(void) mutex_unlock(&child_lock);

		if (ch == NULL) {
			/* Bad slot number */
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "bad slot number %d\n", cslot);

			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
			break;
		}

		if (uid != ch->child_uid) {
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
		(me, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n",
		    uid, ch->child_uid);

			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_CHILD_IMPOSTER);
			break;
		}

		if (ch->child_state != CHILD_STATE_UIDKNOWN &&
		    ch->child_state != CHILD_STATE_FORKSENT) {
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "invalid slot/child state (%d) for uid %d\n",
			    ch->child_state, uid);

			NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
			    NSCD_SELF_CRED_INVALID_SLOT_STATE);
			break;
		}

		_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
		(me, "d_descriptor = %d, d_id = %lld\n",
		    dp->d_data.d_desc.d_descriptor, dp->d_data.d_desc.d_id);

		if ((dp->d_attributes & DOOR_DESCRIPTOR) &&
		    dp->d_data.d_desc.d_descriptor > 0 &&
		    dp->d_data.d_desc.d_id != 0) {
			(void) mutex_lock(ch->mutex);
			if (ch->child_door != -1)
				(void) close(ch->child_door);
			ch->child_door = dp->d_data.d_desc.d_descriptor;
			ch->child_pid  = ucred_getpid(uc);
			ch->child_state  = CHILD_STATE_PIDKNOWN;
			_NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
			(me, "child in slot %d has door %d\n",
			    cslot, ch->child_door);

			/*
			 * let waiters know that the child is ready to
			 * serve
			 */
			(void) cond_broadcast(ch->cond);
			(void) mutex_unlock(ch->mutex);

			/* monitor the child nscd */
			(void) thr_create(NULL, 0, child_monitor,
			    ch, THR_DETACHED, NULL);
			NSCD_SET_STATUS_SUCCESS(phdr);
			break;
		} else {
			NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
		}
		break;
	}

	ucred_free(uc);
	uc = NULL;
}
Beispiel #9
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 #10
0
void
getpw_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now)
{
	int		out_of_date;
	nsc_bucket_t	*retb;
	char 		**bucket;

	static time_t	lastmod;

	int bufferspace = maxsize - sizeof (nsc_return_t);

	if (current_admin.passwd.nsc_enabled == 0) {
		out->nsc_return_code = NOSERVER;
		out->nsc_bufferbytesused = sizeof (*out);
		return;
	}

	mutex_lock(&passwd_lock);

	if (current_admin.passwd.nsc_check_files) {
		struct stat buf;

		if (stat("/etc/passwd", &buf) < 0) {
			/*EMPTY*/;
		} else if (lastmod == 0) {
			lastmod = buf.st_mtime;
		} else if (lastmod < buf.st_mtime) {
			getpw_invalidate_unlocked();
			lastmod = buf.st_mtime;
		}
	}

	if (current_admin.debug_level >= DBG_ALL) {
		if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) {
			logit("getpw_lookup: looking for uid %d\n",
				in->nsc_u.uid);
		} else {
			logit("getpw_lookup: looking for name %s\n",
				in->nsc_u.name);
		}
	}

	for (;;) {
		if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) {
			bucket = get_hash(uid_hash, (char *)in->nsc_u.uid);
		} else { /* make reasonableness check here  */
			if (strlen(in->nsc_u.name) > NSCDMAXNAMELEN) {
				ucred_t *uc = NULL;

				if (door_ucred(&uc) != 0) {
					logit("getpw_lookup: Name too long, "
					    "but no user credential: %s\n",
					    strerror(errno));
				} else {

					logit("getpw_lookup: Name too long "
					    "from pid %d uid %d\n",
					    ucred_getpid(uc),
					    ucred_getruid(uc));
					ucred_free(uc);
				}


				out->nsc_errno = NSS_NOTFOUND;
				out->nsc_return_code = NOTFOUND;
				out->nsc_bufferbytesused = sizeof (*out);
				goto getout;
			}
			bucket = get_hash(nam_hash, in->nsc_u.name);
		}

		if (*bucket == (char *)-1) {	/* pending lookup */
			if (get_clearance(in->nsc_callnumber) != 0) {
				/* no threads available */
				out->nsc_return_code = NOSERVER;
				/* cannot process now */
				out->nsc_bufferbytesused = sizeof (*out);
				current_admin.passwd.nsc_throttle_count++;
				goto getout;
			}
			nscd_wait(&passwd_wait, &passwd_lock, bucket);
			release_clearance(in->nsc_callnumber);
			continue; /* go back and relookup hash bucket */
		}
		break;
	}

	/*
	 * check for no name_service mode
	 */

	if (*bucket == NULL && current_admin.avoid_nameservice) {
		out->nsc_return_code = NOTFOUND;
		out->nsc_bufferbytesused = sizeof (*out);
	} else if (*bucket == NULL ||
	    (in->nsc_callnumber & UPDATEBIT) ||
	    (out_of_date = (!current_admin.avoid_nameservice &&
		(current_admin.passwd.nsc_old_data_ok == 0) &&
		(((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) {
		/*
		 * time has expired
		 */
		int saved_errno;
		int saved_hits = 0;
		struct passwd *p;

		if (get_clearance(in->nsc_callnumber) != 0) {
			/* no threads available */
			out->nsc_return_code = NOSERVER;
			/* cannot process now */
			out->nsc_bufferbytesused = sizeof (*out);
			current_admin.passwd.nsc_throttle_count++;
			goto getout;
		}
		if (*bucket != NULL) {
			saved_hits = ((nsc_bucket_t *)*bucket)->nsc_hits;
		}

		/*
		 *  block any threads accessing this bucket if data
		 *  is non-existent or out of date
		 */

		if (*bucket == NULL || out_of_date) {
			update_pw_bucket((nsc_bucket_t **)bucket,
					(nsc_bucket_t *)-1,
					in->nsc_callnumber);
		} else {
			/*
			 * if still not -1 bucket we are doing
			 * update... mark to prevent pileups of threads if
			 * the name service is hanging..
			 */
			((nsc_bucket_t *)(*bucket))->nsc_status |=
				ST_UPDATE_PENDING;
			/* cleared by deletion of old data */
		}
		mutex_unlock(&passwd_lock);

		if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) {
			p = _uncached_getpwuid_r(in->nsc_u.uid, &out->nsc_u.pwd,
				out->nsc_u.buff+sizeof (struct passwd),
				bufferspace);
			saved_errno = errno;
		} else {
			p = _uncached_getpwnam_r(in->nsc_u.name,
				&out->nsc_u.pwd,
				out->nsc_u.buff+sizeof (struct passwd),
				bufferspace);
			saved_errno = errno;
		}

		mutex_lock(&passwd_lock);

		release_clearance(in->nsc_callnumber);

		if (p == NULL) { /* data not found */
			if (current_admin.debug_level >= DBG_CANT_FIND) {
				if (MASKUPDATEBIT(in->nsc_callnumber) ==
					GETPWUID) {
			logit("getpw_lookup: nscd COULDN'T FIND uid %d\n",
					in->nsc_u.uid);
				} else {
		logit("getpw_lookup: nscd COULDN'T FIND passwd name %s\n",
						in->nsc_u.name);
				}
			}

			if (!(UPDATEBIT & in->nsc_callnumber))
			    current_admin.passwd.nsc_neg_cache_misses++;

			retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t));

			retb->nsc_refcount = 1;
			retb->nsc_data.nsc_bufferbytesused =
				sizeof (nsc_return_t);
			retb->nsc_data.nsc_return_code = NOTFOUND;
			retb->nsc_data.nsc_errno = saved_errno;
			memcpy(out, &retb->nsc_data,
				retb->nsc_data.nsc_bufferbytesused);
			update_pw_bucket((nsc_bucket_t **)bucket, retb,
				in->nsc_callnumber);
			goto getout;
		} else {
			if (current_admin.debug_level >= DBG_ALL) {
				if (MASKUPDATEBIT(in->nsc_callnumber) ==
					GETPWUID) {
				logit("getpw_lookup: nscd FOUND uid %d\n",
						in->nsc_u.uid);
				} else {
			logit("getpw_lookup: nscd FOUND passwd name %s\n",
						in->nsc_u.name);
				}
			}
			if (!(UPDATEBIT & in->nsc_callnumber))
			    current_admin.passwd.nsc_pos_cache_misses++;

			retb = fixbuffer(out, bufferspace);
			update_pw_bucket((nsc_bucket_t **)bucket,
				retb, in->nsc_callnumber);
			if (saved_hits)
				retb->nsc_hits = saved_hits;
		}
	} else { 	/* found entry in cache */
		retb = (nsc_bucket_t *)*bucket;

		retb->nsc_hits++;

		memcpy(out, &(retb->nsc_data),
			retb->nsc_data.nsc_bufferbytesused);

		if (out->nsc_return_code == SUCCESS) {
			if (!(UPDATEBIT & in->nsc_callnumber))
			    current_admin.passwd.nsc_pos_cache_hits++;
			if (current_admin.debug_level >= DBG_ALL) {
				if (MASKUPDATEBIT(in->nsc_callnumber) ==
					GETPWUID) {
			logit("getpw_lookup: found uid %d in cache\n",
						in->nsc_u.uid);
				} else {
			logit("getpw_lookup: found name %s in cache\n",
						in->nsc_u.name);
				}
			}
		} else {
			if (!(UPDATEBIT & in->nsc_callnumber))
			    current_admin.passwd.nsc_neg_cache_hits++;
			if (current_admin.debug_level >= DBG_ALL) {
				if (MASKUPDATEBIT(in->nsc_callnumber) ==
					GETPWUID) {
		logit("getpw_lookup: %d marked as NOT FOUND in cache.\n",
						in->nsc_u.uid);
				} else {
		logit("getpw_lookup: %s marked as NOT FOUND in cache.\n",
						in->nsc_u.name);
				}
			}
		}

		if ((retb->nsc_timestamp < now) &&
			!(in->nsc_callnumber & UPDATEBIT) &&
			!(retb->nsc_status & ST_UPDATE_PENDING)) {
			logit("launch update since time = %d\n",
				retb->nsc_timestamp);
			retb->nsc_status |= ST_UPDATE_PENDING;
			/* cleared by deletion of old data */
			launch_update(in);
		}
	}

getout:

	mutex_unlock(&passwd_lock);

	/*
	 *	secure mode check - blank out passwd if call sucessfull
	 *	and caller != effective id
	 */
	if ((current_admin.passwd.nsc_secure_mode != 0) &&
		(out->nsc_return_code == SUCCESS) &&
		!(UPDATEBIT & in->nsc_callnumber)) {

		ucred_t *uc = NULL;

		if (door_ucred(&uc) != 0) {
			perror("door_ucred");
		} else {
			if (ucred_geteuid(uc) != out->nsc_u.pwd.pw_uid) {
				/*
				 *  write *NP* into passwd field if
				 *  not already that way... we fixed
				 *  the buffer code so there's always room.
				 */
				int len;

				char *foo = out->nsc_u.buff
					+ sizeof (struct passwd)
					+ (int)out->nsc_u.pwd.pw_passwd;

				len = strlen(foo);
				if (len > 0 &&
				    strcmp(foo, "*NP*") != 0 &&
				    strcmp(foo, "x") != 0) {
					if (len < 5)
						len = 5;
					strncpy(foo, "*NP*", len);
					/*
					 * strncpy will
					 * blank all
					 */
				}
			}
			ucred_free(uc);
		}
	}
}
Beispiel #11
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 #12
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;
}
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 #14
0
/*ARGSUSED*/
static void
switcher(void *cookie, char *argp, size_t arg_size,
    door_desc_t *dp, uint_t n_desc)
{
#define	GETSIZE 1000
#define	ALLOCATE 1001

	ldap_call_t	*ptr = (ldap_call_t *)argp;
	ucred_t		*uc = NULL;

	LineBuf		configInfo;
	dataunion	*buf = NULL;
	/*
	 * By default the size of  a buffer to be passed down to a client
	 * is equal to the size of the ldap_return_t structure. We need
	 * a bigger buffer in a few cases.
	 */
	size_t		configSize = sizeof (ldap_return_t);
	int		ldapErrno = 0, state, callnumber;
	struct {
		void	*begin;
		size_t	size;
		uint8_t	destroy;
	} dataSource;

	if (argp == DOOR_UNREF_DATA) {
		logit("Door Slam... invalid door param\n");
		syslog(LOG_ERR, gettext("ldap_cachemgr: Door Slam... "
		    "invalid door param"));
		(void) printf(gettext("Door Slam... invalid door param\n"));
		exit(0);
	}

	if (ptr == NULL) { /* empty door call */
		(void) door_return(NULL, 0, 0, 0); /* return the favor */
	}

	bzero(&dataSource, sizeof (dataSource));

	/*
	 * We presume that sizeof (ldap_return_t) bytes are always available
	 * on the stack
	 */
	callnumber = ptr->ldap_callnumber;

	switch (callnumber) {
		case NULLCALL:
			/*
			 * Just a 'ping'. Use the default size
			 * of the buffer and set the
			 * 'OK' error code.
			 */
			state = ALLOCATE;
			break;
		case GETLDAPCONFIG:
			/*
			 * Get the current LDAP configuration.
			 * Since this is dynamic data and its size can exceed
			 * the size of ldap_return_t, the next step will
			 * calculate who much space exactly is required.
			 */
			getldap_lookup(&configInfo, ptr);

			state = GETSIZE;
			break;
		case GETLDAPSERVER:
			/*
			 * Get the root DSE for a next server in the list.
			 * Since this is dynamic data and its size can exceed
			 * the size of ldap_return_t, the next step will
			 * calculate who much space exactly is required.
			 */
			getldap_getserver(&configInfo, ptr);

			state = GETSIZE;
			break;
		case GETCACHESTAT:
			/*
			 * Get the cache stattistics.
			 * Since this is dynamic data and its size can exceed
			 * the size of ldap_return_t, the next step will
			 * calculate how much space exactly is required.
			 */
			getldap_get_cacheStat(&configInfo);

			state = GETSIZE;
			break;
		case GETADMIN:
			/*
			 * Get current configuration and statistics.
			 * The size of the statistics structure is less then
			 * sizeof (ldap_return_t). So specify the source
			 * where to take the info and proceed with the memory
			 * allocation.
			 */
			state = ALLOCATE;

			if (ldapErrno == 0) {
				dataSource.begin = &current_admin;
				dataSource.size = sizeof (current_admin);
				dataSource.destroy = 0;
			}
			break;
		case KILLSERVER:
			/*
			 * Process the request and proceed with the default
			 * buffer allocation.
			 */
			if (is_root(1, "KILLSERVER", &uc))
				exit(0);

			ldapErrno = -1;
			state = ALLOCATE;
			break;
		case SETADMIN:
			/*
			 * Process the request and proceed with the default
			 * buffer allocation.
			 */
			if (is_root(1, "SETADMIN", &uc))
				ldapErrno = setadmin(ptr);
			else
				ldapErrno = -1;

			state = ALLOCATE;
			break;
		case GETCACHE:
			/*
			 * Get the cache stattistics.
			 * Since this is dynamic data and its size can exceed
			 * the size of ldap_return_t, the next step will
			 * calculate how much space exactly is required.
			 */
			getldap_get_cacheData(&configInfo, ptr);

			state = GETSIZE;
			break;
		case SETCACHE:
			/*
			 * Process the request and proceed with the default
			 * buffer allocation.
			 */
			if (is_root(0, "SETCACHE", &uc) &&
			    is_nscd(ucred_getpid(uc))) {
				ldapErrno = getldap_set_cacheData(ptr);
				current_admin.ldap_stat.ldap_numbercalls++;
			} else
				ldapErrno = -1;

			if (uc != NULL)
				ucred_free(uc);
			state = ALLOCATE;
			break;
		default:
			/*
			 * This means an unknown request type. Proceed with
			 * the default buffer allocation.
			 */
			logit("Unknown ldap service door call op %d\n",
			    ptr->ldap_callnumber);
			ldapErrno = -99;

			state = ALLOCATE;
			break;
	}

	switch (state) {
		case GETSIZE:
			/*
			 * This stage calculates how much data will be
			 * passed down to the client, checks if there is
			 * enough space on the stack to accommodate the data,
			 * increases the value of the configSize variable
			 * if necessary and specifies the data source.
			 * In case of any error occurred ldapErrno will be set
			 * appropriately.
			 */
			if (configInfo.str == NULL) {
				ldapErrno = -1;
			}

			configSize = get_data_size(&configInfo, &ldapErrno);

			if (ldapErrno == 0) {
				dataSource.begin = configInfo.str;
				dataSource.size = configInfo.len;
				dataSource.destroy = 1;
			}

			current_admin.ldap_stat.ldap_numbercalls++;
			/* FALLTHRU */
		case ALLOCATE:
			/*
			 * Allocate a buffer of the calculated (or default) size
			 * and proceed with populating it with data.
			 */
			buf = (dataunion *) alloca(configSize);

			/*
			 * Set a return code and, if a data source is specified,
			 * copy data from the source to the buffer.
			 */
			buf->data.ldap_ret.ldap_errno = ldapErrno;
			buf->data.ldap_ret.ldap_return_code = ldapErrno;
			buf->data.ldap_ret.ldap_bufferbytesused = configSize;

			if (dataSource.begin != NULL) {
				(void) memcpy(buf->data.ldap_ret.ldap_u.config,
				    dataSource.begin,
				    dataSource.size);
				if (dataSource.destroy) {
					free(dataSource.begin);
				}
			}

	}
	(void) door_return((char *)&buf->data,
	    buf->data.ldap_ret.ldap_bufferbytesused,
	    NULL,
	    0);
#undef	GETSIZE
#undef	ALLOCATE
}
Beispiel #15
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 #16
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);
}