--- cups-1.2.8/cups/http.c.scm_credentials 2007-03-08 10:10:38.000000000 +0000 +++ cups-1.2.8/cups/http.c 2007-03-08 10:52:19.000000000 +0000 @@ -109,6 +109,11 @@ # include #endif /* !WIN32 */ +#include +#include +#if !defined(WIN32) && !defined(__EMX__) +# include +#endif /* * Some operating systems have done away with the Fxxxx constants for @@ -2515,6 +2520,58 @@ httpGetLength2(http); httpClearFields(http); +#ifdef SCM_CREDENTIALS + if (!strncmp(http->authstring, "SCM_CREDENTIALS", 15)) + { + struct msghdr msg; + struct cmsghdr *cmsg; + struct iovec vec; + char dummy; + char buf[CMSG_SPACE(sizeof(struct ucred))]; + struct ucred *uptr; + fd_set fds; + struct timeval tv; + + FD_ZERO(&fds); + FD_SET(http->fd, &fds); + tv.tv_sec = 5; /* Wait up to 5 seconds. */ + tv.tv_usec = 0; + if (select(http->fd + 1, &fds, NULL, &fds, &tv) < 1 || + recv(http->fd, &dummy, 1, 0) != 1) + { + DEBUG_printf(("http_send: failed to synchronize for SCM_CREDENTIALS")); + return (-1); + } + + memset (&msg, 0, sizeof(msg)); + vec.iov_base = &dummy; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + 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(struct ucred)); + uptr = (struct ucred *)CMSG_DATA(cmsg); + uptr->uid = getuid(); + uptr->gid = getgid(); + uptr->pid = getpid(); + msg.msg_controllen = cmsg->cmsg_len; + FD_ZERO(&fds); + FD_SET(http->fd, &fds); + tv.tv_sec = 5; + tv.tv_usec = 0; + if (select(http->fd + 1, NULL, &fds, &fds, &tv) < 1 || + sendmsg(http->fd, &msg, 0) == -1) + { + DEBUG_printf(("http_send: failed to send SCM_CREDENTIALS")); + return (-1); + } + } +#endif /* SCM_CREDENTIALS */ + return (0); } --- cups-1.2.8/cups/auth.c.scm_credentials 2007-01-10 16:48:37.000000000 +0000 +++ cups-1.2.8/cups/auth.c 2007-03-08 10:53:43.000000000 +0000 @@ -26,6 +26,9 @@ * Contents: * * cupsDoAuthentication() - Authenticate a request. + * cups_scm_credentials_auth + * - Find out if SCM_CREDENTIALS authentication + * is possible * cups_local_auth() - Get the local authorization certificate if * available/applicable... */ @@ -47,6 +50,8 @@ # include #endif /* WIN32 || __EMX__ */ +#include +#include /* * Local functions... @@ -177,6 +182,57 @@ return (0); } +#ifdef SCM_CREDENTIALS +/* + * 'cups_scm_credentials_auth()' + * - UNIX Domain Sockets authentication + */ + +static int /* O - 0 if available, -1 if not */ +cups_scm_credentials_auth(http_t *http) /* I - HTTP connection to server */ +{ + long buflen; + char *buf; + struct passwd pwbuf, *pwbufptr; + + if (http->hostaddr->addr.sa_family != AF_LOCAL) + return (-1); + + /* + * Are we trying to authenticate as ourselves? If not, SCM_CREDENTIALS + * is no use. + */ + buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + buf = malloc (buflen); + if (buf == NULL) + return (-1); + + if (getpwnam_r (cupsUser(), &pwbuf, buf, buflen, &pwbufptr) != 0) + { + free (buf); + return (-1); + } + + if (pwbuf.pw_uid != getuid()) + { + free (buf); + return (-1); + } + + free (buf); + + /* + * Set the authorization string and return... + */ + + snprintf(http->authstring, sizeof(http->authstring), "SCM_CREDENTIALS"); + + DEBUG_printf(("cups_scm_credentials_auth: Returning authstring = \"%s\"\n", + http->authstring)); + + return (0); +} +#endif /* SCM_CREDENTIALS */ /* * 'cups_local_auth()' - Get the local authorization certificate if @@ -234,7 +290,13 @@ { DEBUG_printf(("cups_local_auth: Unable to open file %s: %s\n", filename, strerror(errno))); + +#ifdef AF_LOCAL + return cups_scm_credentials_auth(http); +#else return (-1); +#endif /* AF_LOCAL */ + } /* --- cups-1.2.8/scheduler/auth.c.scm_credentials 2006-09-12 14:58:39.000000000 +0100 +++ cups-1.2.8/scheduler/auth.c 2007-03-08 10:50:19.000000000 +0000 @@ -80,6 +80,14 @@ # include #endif /* HAVE_MEMBERSHIP_H */ +#include +#include +#include +#include +#if !defined(WIN32) && !defined(__EMX__) +# include +#endif + /* * Local functions... @@ -384,6 +392,99 @@ "cupsdAuthorize: No authentication data provided."); return; } +#ifdef SCM_CREDENTIALS + else if (!strncmp(authorization, "SCM_CREDENTIALS", 3) && + con->http.hostaddr->addr.sa_family == AF_LOCAL) + { + const int val = 1; + struct msghdr msg; + struct cmsghdr *cmsg; + struct iovec vec; + char dummy; + char buf[CMSG_SPACE(sizeof(struct ucred))]; + fd_set fds; + struct timeval tv; + + cupsdLogMessage(CUPSD_LOG_DEBUG, "SCM_CREDENTIALS authentication"); + + /* Turn on reception of credentials. */ + if (setsockopt(con->http.fd, SOL_SOCKET, SO_PASSCRED, &val, sizeof(val))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "SCM_CREDENTIALS setsockopt failed!"); + return; + } + + /* If the client sends their SCM_CREDENTIALS message too soon we will + * read it as part of the HTTP request. To prevent that, they wait + * until we send them this zero byte to synchronize. + */ + dummy = '\0'; + FD_ZERO(&fds); + FD_SET(con->http.fd, &fds); + tv.tv_sec = 5; /* Wait up to 5 seconds */ + tv.tv_usec = 0; + if (select(con->http.fd + 1, NULL, &fds, &fds, &tv) < 1 || + send(con->http.fd, &dummy, 1, 0) != 1) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "SCM_CREDENTIALS sync failed"); + return; + } + + memset (&msg, 0, sizeof(msg)); + vec.iov_base = &dummy; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + FD_ZERO(&fds); + FD_SET(con->http.fd, &fds); + tv.tv_sec = 5; /* Wait up to 5 seconds */ + tv.tv_usec = 0; + if (select(con->http.fd + 1, &fds, NULL, &fds, &tv) < 1 || + recvmsg(con->http.fd, &msg, 0) == -1) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "SCM_CREDENTIALS recvmsg failed!"); + return; + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg,cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS) + { + long buflen; + char *buf; + struct passwd pwbuf, *pwbufptr; + struct ucred *uptr; + + if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "SCM_CREDENTIALS cmsg_len mismatch!"); + return; + } + + uptr = (struct ucred *)CMSG_DATA(cmsg); + + buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + buf = malloc (buflen); + if (buf == NULL) + return; + + /* Look up which username the UID is for. */ + if (getpwuid_r (uptr->uid, &pwbuf, buf, buflen, &pwbufptr) != 0) + { + free (buf); + return; + } + + strlcpy(username, pwbuf.pw_name, sizeof(username)); + free (buf); + } + } + } +#endif /* SCM_CREDENTIALS */ else if (!strncmp(authorization, "Local", 5) && !strcasecmp(con->http.hostname, "localhost")) {