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); }
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; }
/* * picld_wait is called when a picl_wait request is received */ static void picld_wait(picl_service_t *in) { picl_retwait_t ret; int err; ucred_t *puc = NULL; uid_t uid; ret.cnum = in->req_wait.cnum; if (door_ucred(&puc) != 0) ret.retcode = PICL_FAILURE; else { uid = ucred_geteuid(puc); if (enter_picld_wait(uid) == PICL_FAILURE) ret.retcode = PICL_FAILURE; else { err = xptree_refresh_notify(in->req_wait.secs); ret.retcode = err; exit_picld_wait(uid); } ucred_free(puc); } (void) rw_unlock(&init_lk); (void) door_return((char *)&ret, sizeof (picl_retwait_t), NULL, 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); }
// Calls from the door function to check that the client credentials // match this process. Returns 0 if credentials okay, otherwise -1. static int check_credentials() { ucred_t *cred_info = NULL; int ret = -1; // deny by default // get client credentials if (door_ucred(&cred_info) == -1) { return -1; // unable to get them, deny } // get our euid/eguid (probably could cache these) uid_t euid = geteuid(); gid_t egid = getegid(); // get euid/egid from ucred_free uid_t ucred_euid = ucred_geteuid(cred_info); gid_t ucred_egid = ucred_getegid(cred_info); // check that the effective uid/gid matches if (ucred_euid == euid && ucred_egid == egid) { ret = 0; // allow } ucred_free(cred_info); return ret; }
/* * 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 }
/* * 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; }
/* * 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 }
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); }
/* 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; }
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 ; }
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); } }
/*ARGSUSED*/ void _nscd_peruser_getadmin( void *buf, int buf_size) { void *result_mn = NSCD_N2N_DOOR_DATA(void, buf); int errnum = 0; int ret; uid_t uid; nss_pheader_t *phdr = (nss_pheader_t *)buf; char *me = "_nscd_peruser_getadmin"; ucred_t *uc = NULL; child_t *ch; /* get door client's credential information */ 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); } /* get door client's effective uid */ uid = ucred_geteuid(uc); ucred_free(uc); uc = NULL; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "per user get admin ... (uid = %d)\n", uid); /* is the per-user nscd running ? if not, no one to serve */ ch = get_cslot(uid, 1); if (ch == NULL) { NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_NO_CHILD_SLOT); } ret = _nscd_doorcall_fd(ch->child_door, NSCD_GETADMIN, NULL, sizeof (nscd_admin_t), result_mn, sizeof (nscd_admin_t), phdr); if (ret == NSS_SUCCESS) { phdr->data_len = sizeof (nscd_admin_t); return; } }
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); }
uid_t _nscd_get_client_euid() { ucred_t *uc = NULL; uid_t id; char *me = "get_client_euid"; if (door_ucred(&uc) != 0) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door_ucred: %s\n", strerror(errno)); return ((uid_t)-1); } id = ucred_geteuid(uc); ucred_free(uc); return (id); }
/* * check_auth() * * Perform an RBAC authorization check. */ static int check_auth(ucred_t *ucred, const char *auth) { struct passwd pwd; uid_t euid; char buf[MAXPATHLEN]; euid = ucred_geteuid(ucred); if ((getpwuid_r(euid, &pwd, buf, sizeof (buf)) == NULL) || (chkauthattr(auth, pwd.pw_name) == 0)) { log_info("Unauthorized door call.\n"); return (-1); } return (0); }
/* * Check to see if the door client's euid is 0 or if it has required_priv * privilege. Return 0 if yes, -1 otherwise. * Supported values for required_priv are: * - NSCD_ALL_PRIV: for all zones privileges * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege */ int _nscd_check_client_priv(int required_priv) { int rc = 0; ucred_t *uc = NULL; const priv_set_t *eset; char *me = "_nscd_check_client_read_priv"; priv_set_t *zs; /* zone */ if (door_ucred(&uc) != 0) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "door_ucred: %s\n", strerror(errno)); return (-1); } if (ucred_geteuid(uc) == 0) { ucred_free(uc); return (0); } eset = ucred_getprivset(uc, PRIV_EFFECTIVE); switch (required_priv) { case NSCD_ALL_PRIV: zs = priv_str_to_set("zone", ",", NULL); if (!priv_isequalset(eset, zs)) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "missing all zones privileges\n"); rc = -1; } priv_freeset(zs); break; case NSCD_READ_PRIV: if (!priv_ismember(eset, PRIV_FILE_DAC_READ)) rc = -1; break; default: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "unknown required_priv: %d\n", required_priv); rc = -1; break; } ucred_free(uc); return (rc); }
/* * 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; }
/** * 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; }
void _nscd_proc_alt_get( void *buf, int *door) { int errnum; uid_t set2uid; gid_t set2gid; nss_pheader_t *phdr = (nss_pheader_t *)buf; char *me = "_nscd_proc_alt_get"; ucred_t *uc = NULL; child_t *ch; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "getting an alternate door ...\n"); /* make sure there is a door to talk to the forker */ if (forking_door == -1) { _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) (me, "no door to talk to the forker\n"); NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_NO_FORKER); } /* get door client's credential information */ 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); } /* get door client's effective uid and effective gid */ set2uid = ucred_geteuid(uc); set2gid = ucred_getegid(uc); ucred_free(uc); uc = NULL; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "child uid = %d, gid = %d\n", set2uid, set2gid); /* is a slot available ? if not, no one to serve */ if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) { _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "no child slot available (child array = %p, slot = %d)\n", child, ch->child_slot); NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_NO_CHILD_SLOT); } /* create the per user nscd if necessary */ if (ch->child_state != CHILD_STATE_PIDKNOWN) { nss_pheader_t phdr1; NSCD_CLEAR_STATUS(&phdr1); (void) mutex_lock(ch->mutex); if (ch->child_state == CHILD_STATE_UIDKNOWN) { /* ask forker to fork a new child */ selfcred_fork(&phdr1, forking_door, ch->child_slot, set2uid, set2gid); if (NSCD_STATUS_IS_NOT_OK(&phdr1)) { (void) mutex_unlock(ch->mutex); NSCD_COPY_STATUS(phdr, &phdr1); return; } ch->child_state = CHILD_STATE_FORKSENT; } _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "waiting for door (slot = %d, uid = %d, gid = %d)\n", ch->child_slot, set2uid, set2gid); /* wait for the per user nscd to become available */ while (ch->child_state == CHILD_STATE_FORKSENT) { timestruc_t to; int err; int ttl = 5; to.tv_sec = ttl; to.tv_nsec = 0; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "cond_reltimedwait %d seconds\n", ttl); err = cond_reltimedwait(ch->cond, ch->mutex, &to); if (err == ETIME) { ch->child_state = CHILD_STATE_UIDKNOWN; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "door wait timedout (slot = %d)\n", ch->child_slot); break; } } (void) mutex_unlock(ch->mutex); } if (ch->child_state != CHILD_STATE_PIDKNOWN) { NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_INVALID_SLOT_STATE); } *door = ch->child_door; _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) (me, "returning door %d for slot %d, uid %d, gid = %d\n", *door, ch->child_slot, set2uid, set2gid); NSCD_RETURN_STATUS(phdr, NSS_ALTRETRY, 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; }
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); }
/* * check_auth_modify() checks if a given cred has * the authorization to add/change/remove configuration values. * cred is from the door call. */ Boolean_t check_auth_modify(ucred_t *cred) { targ_scf_t *h = NULL; Boolean_t ret = False; int exit_code = -1; uid_t uid; gid_t gid; pid_t pid; tgt_node_t *n = NULL; scf_transaction_entry_t *ent = NULL; const priv_set_t *eset; pid = fork(); switch (pid) { case 0: /* Child process to check authorization */ uid = ucred_geteuid(cred); if (seteuid(uid) != 0) { syslog(LOG_ERR, "not priviliged\n"); exit(-1); } gid = ucred_getegid(cred); if (setegid(gid) != 0) { syslog(LOG_ERR, "not priviliged\n"); exit(-1); } eset = ucred_getprivset(cred, PRIV_EFFECTIVE); setppriv(PRIV_ON, PRIV_EFFECTIVE, eset); h = mgmt_handle_init(); if (h == NULL) { exit(-1); } if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { n = tgt_node_alloc("dummy", String, "dummy"); new_property(h, n); tgt_node_free(n); if (mgmt_transaction_end(h) == True) { exit_code = 0; } else { exit_code = -1; } } else { exit_code = -1; } if (exit_code != 0) { mgmt_handle_fini(h); exit(exit_code); } if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { ent = scf_entry_create(h->t_handle); if (ent) { scf_transaction_property_delete(h->t_trans, ent, "dummy"); } } mgmt_transaction_end(h); mgmt_handle_fini(h); exit(exit_code); break; case -1: /* Fail to fork */ exit(SMF_EXIT_ERR_CONFIG); default: wait(&exit_code); exit_code = exit_code >> 8; if (exit_code == 0) ret = True; else ret = False; break; } return (ret); }
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; }
/*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); }
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; }
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 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; }
/* * remove_zfs -- unshare a ZVOL from the target */ static char * remove_zfs(tgt_node_t *x, ucred_t *cred) { char *prop; char *msg = NULL; tgt_node_t *targ = NULL; libzfs_handle_t *zh = NULL; const priv_set_t *eset; if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); return (msg); } if ((zh = libzfs_init()) == NULL) { xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); free(prop); return (msg); } eset = ucred_getprivset(cred, PRIV_EFFECTIVE); if (eset != NULL ? !priv_ismember(eset, PRIV_SYS_CONFIG) : ucred_geteuid(cred) != 0) { /* * See if user has ZFS dataset permissions to do operation */ if (zfs_iscsi_perm_check(zh, prop, cred) != 0) { xml_rtn_msg(&msg, ERR_NO_PERMISSION); free(prop); libzfs_fini(zh); return (msg); } } libzfs_fini(zh); while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ)) != NULL) { if (strcmp(targ->x_value, prop) == 0) break; } free(prop); if (targ == NULL) { /* * We're unsharing a target. If we don't have a reference * then there's no problem. */ xml_rtn_msg(&msg, ERR_SUCCESS); return (msg); } if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) == False) { xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); return (msg); } tgt_node_remove(targets_config, targ, MatchBoth); /* * Wait until here to issue a logout to any initiators that * might be logged into the target. Certain initiators are * sneaky in that if asked to logout they will, but turn right * around and log back into the target. By waiting until here * to issue the logout we'll have removed reference to the target * such that this can't happen. */ if (isns_enabled() == True) { if (isns_dereg(prop) != 0) syslog(LOG_INFO, "ISNS dereg failed\n"); } logout_targ(prop); free(prop); xml_rtn_msg(&msg, ERR_SUCCESS); return (msg); }