new->close = 0;
new->remote = NULL;
new->remotelen = 0;
+ memset(&new->ucred, 0, sizeof(new->ucred));
switch(type)
{
case SOCK_STREAM:
return(NULL);
}
+static void recvcmsg(struct socket *sk, struct msghdr *msg)
+{
+ struct cmsghdr *cmsg;
+ struct ucred *cred;
+
+ for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
+ {
+ if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_CREDENTIALS))
+ {
+ if(sk->ucred.pid == 0)
+ {
+ cred = (struct ucred *)CMSG_DATA(cmsg);
+ memcpy(&sk->ucred, cred, sizeof(*cred));
+ flog(LOG_INFO, "received Unix creds: pid %i, uid %i, gid %i", cred->pid, cred->uid, cred->gid);
+ }
+ }
+ }
+}
+
static void sockrecv(struct socket *sk)
{
int ret, inq;
struct dgrambuf *dbuf;
+ struct msghdr msg;
+ char cbuf[65536];
+ struct iovec bufvec;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &bufvec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
switch(sk->type)
{
case SOCK_STREAM:
if(inq > 65536)
inq = 65536;
sizebuf(&sk->inbuf.s.buf, &sk->inbuf.s.bufsize, sk->inbuf.s.datasize + inq, 1, 1);
+ /*
ret = read(sk->fd, sk->inbuf.s.buf + sk->inbuf.s.datasize, inq);
+ */
+ bufvec.iov_base = sk->inbuf.s.buf + sk->inbuf.s.datasize;
+ bufvec.iov_len = inq;
+ ret = recvmsg(sk->fd, &msg, 0);
if(ret < 0)
{
if((errno == EINTR) || (errno == EAGAIN))
closesock(sk);
return;
}
+ if(msg.msg_flags & MSG_CTRUNC)
+ flog(LOG_DEBUG, "ancillary data was truncated");
+ else
+ recvcmsg(sk, &msg);
if(ret == 0)
{
if(sk->errcb != NULL)
sk->readcb(sk, sk->data);
break;
case SOCK_DGRAM:
+#if defined(HAVE_LINUX_SOCKIOS_H) && defined(SIOCINQ)
if(ioctl(sk->fd, SIOCINQ, &inq))
{
/* I don't really know what could go wrong here, so let's
flog(LOG_WARNING, "SIOCINQ return %s on socket %i", strerror(errno), sk->fd);
return;
}
+#else
+ inq = 65536;
+#endif
dbuf = smalloc(sizeof(*dbuf));
dbuf->data = smalloc(inq);
dbuf->addr = smalloc(dbuf->addrlen = sizeof(struct sockaddr_storage));
+ /*
ret = recvfrom(sk->fd, dbuf->data, inq, 0, dbuf->addr, &dbuf->addrlen);
+ */
+ msg.msg_name = dbuf->addr;
+ msg.msg_namelen = dbuf->addrlen;
+ bufvec.iov_base = dbuf->data;
+ bufvec.iov_len = inq;
+ ret = recvmsg(sk->fd, &msg, 0);
+ dbuf->addrlen = msg.msg_namelen;
if(ret < 0)
{
free(dbuf->addr);
closesock(sk);
return;
}
+ if(msg.msg_flags & MSG_CTRUNC)
+ flog(LOG_DEBUG, "ancillary data was truncated");
+ else
+ recvcmsg(sk, &msg);
/* On UDP/IPv[46], ret == 0 doesn't mean EOF (since UDP can't
* have EOF), but rather an empty packet. I don't know if any
* other potential DGRAM protocols might have an EOF
return(NULL);
}
+static void acceptunix(struct socket *sk)
+{
+ int buf;
+
+ buf = 1;
+ if(setsockopt(sk->fd, SOL_SOCKET, SO_PASSCRED, &buf, sizeof(buf)) < 0)
+ flog(LOG_WARNING, "could not enable SO_PASSCRED on Unix socket %i: %s", sk->fd, strerror(errno));
+}
+
int pollsocks(int timeout)
{
int i, num, ret;
newsk->state = SOCK_EST;
memcpy(newsk->remote = smalloc(sslen), &ss, sslen);
newsk->remotelen = sslen;
- putsock(newsk);
+ if(ss.ss_family == PF_UNIX)
+ acceptunix(newsk);
if(sk->acceptcb != NULL)
sk->acceptcb(sk, newsk, sk->data);
+ putsock(newsk);
}
if(pfds[i].revents & POLLERR)
{
static int fd = -1;
static iconv_t ichandle;
static int resetreader = 1;
-static char *dchostname = NULL;
static struct addrinfo *hostlist = NULL, *curhost = NULL;
+struct {
+ char *hostname;
+ int family;
+ int sentcreds;
+} servinfo;
static struct dc_response *makeresp(void)
{
while((resp = dc_getresp()) != NULL)
dc_freeresp(resp);
dc_uimisc_disconnected();
- if(dchostname != NULL)
- free(dchostname);
- dchostname = NULL;
+ if(servinfo.hostname != NULL)
+ free(servinfo.hostname);
+ memset(&servinfo, 0, sizeof(servinfo));
}
void dc_freeresp(struct dc_response *resp)
}
}
if(curhost->ai_canonname != NULL)
- dchostname = sstrdup(curhost->ai_canonname);
+ servinfo.hostname = sstrdup(curhost->ai_canonname);
+ servinfo.family = curhost->ai_family;
state = 1;
resetreader = 1;
break;
return(0);
}
+static void mkcreds(struct msghdr *msg)
+{
+ struct ucred *ucred;
+ static char buf[CMSG_SPACE(sizeof(*ucred))];
+ struct cmsghdr *cmsg;
+
+ msg->msg_control = buf;
+ msg->msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_CREDENTIALS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*ucred));
+ ucred = (struct ucred *)CMSG_DATA(cmsg);
+ ucred->pid = getpid();
+ ucred->uid = getuid();
+ ucred->gid = getgid();
+ msg->msg_controllen = cmsg->cmsg_len;
+}
+
int dc_handlewrite(void)
{
int ret;
int errnobak;
+ struct msghdr msg;
+ struct iovec bufvec;
switch(state)
{
case 1:
if(queue->buflen > 0)
{
- ret = send(fd, queue->buf, queue->buflen, MSG_NOSIGNAL | MSG_DONTWAIT);
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &bufvec;
+ msg.msg_iovlen = 1;
+ bufvec.iov_base = queue->buf;
+ bufvec.iov_len = queue->buflen;
+ if((servinfo.family == PF_UNIX) && !servinfo.sentcreds)
+ {
+ mkcreds(&msg);
+ servinfo.sentcreds = 1;
+ }
+ ret = sendmsg(fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT);
if(ret < 0)
{
if((errno == EAGAIN) || (errno == EINTR))
fd = -1;
} else {
if(curhost->ai_canonname != NULL)
- dchostname = sstrdup(curhost->ai_canonname);
+ servinfo.hostname = sstrdup(curhost->ai_canonname);
+ servinfo.family = curhost->ai_family;
state = 1;
break;
}
const char *dc_gethostname(void)
{
- return(dchostname);
+ return(servinfo.hostname);
}