/* * 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 }
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 get_peer_label(int fd, char **slabel) { if (is_system_labeled()) { ucred_t *uc = NULL; m_label_t *sl; char *pslabel = NULL; /* peer's slabel */ if ((fd < 0) || (slabel == NULL)) { errno = EINVAL; return (-1); } if (getpeerucred(fd, &uc) == -1) return (-1); sl = ucred_getlabel(uc); if (label_to_str(sl, &pslabel, M_INTERNAL, DEF_NAMES) != 0) syslog(LOG_WARNING, "label_to_str(): %m"); ucred_free(uc); if (pslabel != NULL) { syslog(LOG_DEBUG, "get_peer_label(%d, %s): becomes %s", fd, (*slabel ? *slabel : "NULL"), pslabel); if (*slabel != NULL) free(*slabel); *slabel = strdup(pslabel); } } return (0); }
/* * 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 }
/** * 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); }
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; }
/* 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 ; }
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); }
static int retrievePeerCredentials (PeerCredentials *credentials, int fd) { *credentials = NULL; if (getpeerucred(fd, credentials) == -1) { logSystemError("getpeerucred"); return 0; } #ifdef HAVE_GETZONEID if (ucred_getzoneid(*credentials) != getzoneid()) { ucred_free(*credentials); return 0; } #endif /* HAVE_GETZONEID */ return 1; }
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; }
static int ctrls_get_creds_peerucred(int sockfd, uid_t *uid, gid_t *gid) { ucred_t *cred = NULL; if (getpeerucred(sockfd, &cred) < 0) { int xerrno = errno; pr_trace_msg(trace_channel, 7, "error obtaining credentials using " "getpeerucred(3) on fd %d: %s", sockfd, strerror(xerrno)); errno = xerrno; return -1; } if (uid) *uid = ucred_getruid(cred); if (gid) *gid = ucred_getrgid(cred); ucred_free(cred); return 0; }
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); }
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; }
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; }
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 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; }
/* * Accept a new client request. A struct ilbd_client_t is allocated to * store the client info. The accepted socket is port_associate() with * the given port. And the allocated ilbd_client_t struct is passed as * the user pointer. */ static void new_req(int ev_port, int listener, void *ev_obj) { struct sockaddr sa; int sa_len; int new_sd; int sflags; ilbd_client_t *cli; int res; uid_t uid; sa_len = sizeof (sa); if ((new_sd = accept(listener, &sa, &sa_len)) == -1) { /* don't log if we're out of file descriptors */ if (errno != EINTR && errno != EMFILE) logperror("new_req: accept failed"); goto done; } /* Set the new socket to be non-blocking. */ if ((sflags = fcntl(new_sd, F_GETFL, 0)) == -1) { logperror("new_req: fcntl(F_GETFL)"); goto clean_up; } if (fcntl(new_sd, F_SETFL, sflags | O_NONBLOCK) == -1) { logperror("new_req: fcntl(F_SETFL)"); goto clean_up; } if (fcntl(new_sd, F_SETFD, FD_CLOEXEC) == -1) { logperror("new_req: fcntl(FD_CLOEXEC)"); goto clean_up; } if ((cli = calloc(1, sizeof (ilbd_client_t))) == NULL) { logerr("new_req: malloc(ilbd_client_t)"); goto clean_up; } res = getpeerucred(new_sd, &cli->cli_peer_ucredp); if (res == -1) { logperror("new_req: getpeerucred failed"); goto clean_up; } if ((uid = ucred_getruid(cli->cli_peer_ucredp)) == (uid_t)-1) { logperror("new_req: ucred_getruid failed"); goto clean_up; } cli->cli_pw_bufsz = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX); if ((cli->cli_pw_buf = malloc(cli->cli_pw_bufsz)) == NULL) { free(cli); logerr("new_req: malloc(cli_pw_buf)"); goto clean_up; } if (getpwuid_r(uid, &cli->cli_pw, cli->cli_pw_buf, cli->cli_pw_bufsz) == NULL) { free(cli->cli_pw_buf); free(cli); logperror("new_req: invalid user"); goto clean_up; } cli->cli_ev = ILBD_EVENT_REQ; cli->cli_sd = new_sd; cli->cli_cmd = ILBD_BAD_CMD; cli->cli_saved_reply = NULL; cli->cli_saved_size = 0; if (port_associate(ev_port, PORT_SOURCE_FD, new_sd, POLLRDNORM, cli) == -1) { logperror("new_req: port_associate(cli) failed"); free(cli->cli_pw_buf); free(cli); clean_up: (void) close(new_sd); } done: /* Re-associate the listener with the event port. */ if (port_associate(ev_port, PORT_SOURCE_FD, listener, POLLRDNORM, ev_obj) == -1) { logperror("new_req: port_associate(listener) failed"); exit(1); } }
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; }
/* * 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 }
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; }
/** * 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; }
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); }
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); }