ucred_t * _ucred_alloc(void) { ucred_t *r; size_t sz = ucred_size(); r = malloc(sz); if (r != NULL) r->uc_size = (uint32_t)sz; return (r); }
/* * Check to see if we have the permissions to set scheduler parameters and * policy, based on Linux' demand that such commands fail with errno set to * EPERM if the current euid is not the euid or ruid of the process in * question. */ static int check_schedperms(pid_t pid) { size_t sz; ucred_t *cr; uid_t euid; euid = geteuid(); if (pid == getpid()) { /* * If we're the process to be checked, simply check the euid * against our ruid. */ if (euid != getuid()) return (-EPERM); return (0); } /* * We allocate a ucred_t ourselves rather than call ucred_get(3C) * because ucred_get() calls malloc(3C), which the brand library cannot * use. Because we allocate the space with SAFE_ALLOCA(), there's * no need to free it when we're done. */ sz = ucred_size(); cr = (ucred_t *)SAFE_ALLOCA(sz); if (cr == NULL) return (-ENOMEM); /* * If we can't access the process' credentials, fail with errno EPERM * as the call would not have succeeded anyway. */ if (syscall(SYS_ucredsys, UCREDSYS_UCREDGET, pid, cr) != 0) return ((errno == EACCES) ? -EPERM : -errno); if ((euid != ucred_geteuid(cr)) && (euid != ucred_getruid(cr))) return (-EPERM); return (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; }
/* * Utillity function to fetch the XPRT's ucred and determine if we should deny * the request. For now, we implement a simple policy of rejecting any caller * who does not have the PRIV_SYS_CONFIG bit in their Effective privilege set, * unless the caller is loading a module, which requires all privileges. */ int fmd_rpc_deny(struct svc_req *rqp) { ucred_t *ucp = alloca(ucred_size()); const priv_set_t *psp; if (svc_getcallerucred(rqp->rq_xprt, &ucp) != 0 || (psp = ucred_getprivset(ucp, PRIV_EFFECTIVE)) == NULL) return (1); /* deny access if we can't get credentials */ #ifndef DEBUG /* * For convenience of testing, we only require all privileges for a * module load when running a non-DEBUG fault management daemon. */ if (rqp->rq_proc == FMD_ADM_MODLOAD) return (!priv_isfullset(psp)); #endif return (!priv_ismember(psp, PRIV_SYS_CONFIG)); }
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); }
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); }