Hi,

This is in reference to bz #230613. Since LSPP eval is being done with local
CUPS queue via af_unix sockets, there is a chance to reliably get user
credentials and solve this problem. There is some text describing the design
of this patch here:

http://cyberelk.net/tim/2007/03/08/cups-unix-domain-sockets-authentication/

Below is the patch that should fix the problem. Comments? The patch is
integrated with cups-1.2.8-4.fc7 (rawhide) if you wanted to test it right now. I
will get a patched copy in LSPP repo soon, but would like some feedback as
to whether or not the problem is solved.

Thanks,
-Steve


--- 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 <sys/resource.h>
 #endif /* !WIN32 */
 
+#include <sys/socket.h>
+#include <sys/types.h>
+#if !defined(WIN32) && !defined(__EMX__)
+#  include <unistd.h>
+#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 <unistd.h>
 #endif /* WIN32 || __EMX__ */
 
+#include <sys/types.h>
+#include <pwd.h>
 
 /*
  * 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 <membership.h>
 #endif /* HAVE_MEMBERSHIP_H */
 
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <pwd.h>
+#if !defined(WIN32) && !defined(__EMX__)
+#  include <unistd.h>
+#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"))
   {

--
redhat-lspp mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/redhat-lspp

Reply via email to