/* * 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 }
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; }
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); } }
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); }
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); }
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; 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); }
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); } } }
/* * 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 }
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; }
/*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 = ¤t_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 }
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; }
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); }