Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 6a81cbf6b49b1244542bc09fce02049a > files > 21

cups-1.3.7-30.el5_9.3.src.rpm

diff -up cups-1.3.7/doc/help/ref-cupsd-conf.html.in.CVE-2012-5519 cups-1.3.7/doc/help/ref-cupsd-conf.html.in
--- cups-1.3.7/doc/help/ref-cupsd-conf.html.in.CVE-2012-5519	2013-02-15 09:55:37.506200796 +0000
+++ cups-1.3.7/doc/help/ref-cupsd-conf.html.in	2013-02-15 09:56:23.088451695 +0000
@@ -840,6 +840,29 @@ permissions to use when writing configur
 is @CUPS_CONFIG_FILE_PERM@.</P>
 
 
+<H2 CLASS="title"><A NAME="ConfigurationChangeRestriction">ConfigurationChangeRestriction</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ConfigurationChangeRestriction all
+ConfigurationChangeRestriction root-only
+ConfigurationChangeRestriction none
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ConfigurationChangeRestriction</CODE> directive specifies
+the degree of restriction for changes to cupsd.conf.  Keywords dealing
+with filenames, paths, and users are security-sensitive. Changes to
+them via HTTP are forbidden by default (<CODE>all</CODE>). The value
+<CODE>none</CODE> removes any restriction altogether (note that this
+is unsafe). The value <CODE>root-only</CODE> allows only users
+authorised as user "root" to adjust security-sensitive configuration
+settings, but note that users adjusting settings using polkit (via
+cups-pk-helper) are authenticated as user "root".</P>
+
+
 <H2 CLASS="title"><A NAME="DataDir">DataDir</A></H2>
 
 <H3>Examples</H3>
diff -up cups-1.3.7/man/cupsctl.man.CVE-2012-5519 cups-1.3.7/man/cupsctl.man
--- cups-1.3.7/man/cupsctl.man.CVE-2012-5519	2007-07-11 22:46:42.000000000 +0100
+++ cups-1.3.7/man/cupsctl.man	2013-02-15 09:56:23.089451701 +0000
@@ -90,7 +90,8 @@ Disable printer sharing:
     cupsctl --no-shared-printers
 .fi
 .LP
-Enable printing using the file: pseudo-device:
+Enable printing using the file: pseudo-device (note that this is
+forbidden by default):
 .nf
     cupsctl FileDevice=Yes
 .fi
diff -up cups-1.3.7/man/cupsd.conf.man.in.CVE-2012-5519 cups-1.3.7/man/cupsd.conf.man.in
--- cups-1.3.7/man/cupsd.conf.man.in.CVE-2012-5519	2013-02-15 09:55:37.507200802 +0000
+++ cups-1.3.7/man/cupsd.conf.man.in	2013-02-15 09:56:23.090451706 +0000
@@ -204,6 +204,21 @@ ConfigFilePerm mode
 Specifies the permissions for all configuration files that the scheduler
 writes.
 .TP 5
+ConfigurationChangeRestriction all
+.TP 5
+ConfigurationChangeRestriction root-only
+.TP 5
+ConfigurationChangeRestriction none
+.br
+Specifies the degree of restriction for changes to cupsd.conf.
+Keywords dealing with filenames, paths, and users are
+security-sensitive. Changes to them via HTTP are forbidden by default
+("all"). The value "none" removes any restriction altogether (note
+that this is unsafe). The value "root-only" allows only users
+authorised as user "root" to adjust security-sensitive configuration
+settings, but note that users adjusting settings using polkit (via
+cups-pk-helper) are authenticated as user "root".
+.TP 5
 DataDir path
 .br
 Specified the directory where data files can be found.
diff -up cups-1.3.7/scheduler/client.c.CVE-2012-5519 cups-1.3.7/scheduler/client.c
--- cups-1.3.7/scheduler/client.c.CVE-2012-5519	2013-02-15 09:55:37.683201770 +0000
+++ cups-1.3.7/scheduler/client.c	2013-02-15 09:55:37.718201963 +0000
@@ -1671,13 +1671,10 @@ cupsdReadClient(cupsd_client_t *con)	/*
 	    * Validate the resource name...
 	    */
 
-            if (strncmp(con->uri, "/admin/conf/", 12) ||
-	        strchr(con->uri + 12, '/') ||
-		strlen(con->uri) == 12)
+            if (strcmp(con->uri, "/admin/conf/cupsd.conf"))
 	    {
 	     /*
-	      * PUT can only be done to configuration files under
-	      * /admin/conf...
+	      * PUT can only be done to the cupsd.conf file...
 	      */
 
 	      if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
@@ -3667,6 +3664,9 @@ install_conf_file(cupsd_client_t *con)	/
   snprintf(newfile, sizeof(newfile), "%s%s.N", ServerRoot, con->uri + 11);
   snprintf(oldfile, sizeof(oldfile), "%s%s.O", ServerRoot, con->uri + 11);
 
+  if (!cupsdCheckConfigurationAllowed (con))
+    return (HTTP_FORBIDDEN);
+
   cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...", conffile);
 
  /*
diff -up cups-1.3.7/scheduler/conf.c.CVE-2012-5519 cups-1.3.7/scheduler/conf.c
--- cups-1.3.7/scheduler/conf.c.CVE-2012-5519	2013-02-15 09:55:37.650201589 +0000
+++ cups-1.3.7/scheduler/conf.c	2013-02-15 09:55:37.719201968 +0000
@@ -2878,6 +2878,23 @@ read_configuration(cups_file_t *fp)	/* I
       cupsdLogMessage(CUPSD_LOG_INFO, "Polling %s:%d", pollp->hostname,
 	              pollp->port);
     }
+    else if (!strcasecmp(line, "ConfigurationChangeRestriction") && value)
+    {
+      if (!strcasecmp(value, "none"))
+	ConfigurationChangeRestriction = CUPSD_CONFRESTRICT_NONE;
+      else if (!strcasecmp(value, "root-only"))
+	ConfigurationChangeRestriction = CUPSD_CONFRESTRICT_ROOT;
+      else if (!strcasecmp(value, "all"))
+	ConfigurationChangeRestriction = CUPSD_CONFRESTRICT_ALL;
+      else
+      {
+	cupsdLogMessage(CUPSD_LOG_WARN,
+	                "Unknown restriction type %s on line %d.",
+	                value, linenum);
+	if (FatalErrors & CUPSD_FATAL_CONFIG)
+	  return (0);
+      }
+    }
     else if (!strcasecmp(line, "DefaultAuthType"))
     {
      /*
@@ -3263,6 +3280,245 @@ read_configuration(cups_file_t *fp)	/* I
   return (1);
 }
 
+static cups_array_t *
+_cupsdGetBlacklistedConfLines(cups_file_t *fp)
+{
+  cups_array_t *conf;
+  int linenum;
+  char keyword[HTTP_MAX_BUFFER],
+    *temp,
+    *value;
+  const char **kw;
+  size_t len;
+  const char *blacklist[] = {
+    "ConfigurationChangeRestriction",
+    "AccessLog",
+    "BrowseLDAPCACertFile",
+    "CacheDir",
+    "ConfigFilePerm",
+    "DataDir",
+    "DocumentRoot",
+    "ErrorLog",
+    "FatalErrors",
+    "FileDevice",
+    "FontPath",
+    "Group",
+    "LogFilePerm",
+    "LPDConfigFile",
+    "PageLog",
+    "Printcap",
+    "PrintcapFormat",
+    "PrintcapGUI",
+    "RemoteRoot",
+    "RequestRoot",
+    "ServerBin",
+    "ServerCertificate",
+    "ServerKey",
+    "ServerRoot",
+    "SMBConfigFile",
+    "StateDir",
+    "SystemGroup",
+    "SystemGroupAuthKey",
+    "TempDir",
+    "User",
+    NULL
+  };
+
+  conf = cupsArrayNew (NULL, NULL);
+
+ /*
+  * Loop through each line in the file...
+  */
+
+  linenum = 0;
+
+  while (cupsFileGetConf(fp, keyword, sizeof(keyword), &value, &linenum))
+  {
+    for (kw = blacklist; *kw; kw++)
+      if (!strcasecmp (keyword, *kw))
+	break;
+
+    if (*kw == NULL)
+      continue;
+
+   /*
+    * Remember lines we might need to compare against, but only the
+    * last occurrence of each keyword, except for
+    * SystemGroup. SystemGroup is special because it is cumulative:
+    * each SystemGroup line adds groups to the list. For that reason,
+    * we remember multiple SystemGroup lines and don't care about the
+    * order...
+    */
+
+    len = strlen (keyword);
+    if (strcasecmp(keyword, "SystemGroup") != 0)
+    {
+      for (temp = (char *) cupsArrayFirst(conf);
+	   temp;
+	   temp = (char *) cupsArrayNext(conf))
+      {
+	if (!strncasecmp (temp, keyword, len) && temp[len] == ' ')
+	{
+	  cupsArrayRemove(conf, temp);
+
+	  /*
+	   * There can only be one such line because we do this for each
+	   * line containing a blacklisted keyword
+	   */
+
+	  break;
+	}
+      }
+    }
+
+    len += (value ? strlen (value) : 0) + 2;
+    temp = malloc (len);
+    if (!temp)
+      goto fail;
+
+    snprintf (temp, len, "%s %s", keyword, value ? value : "");
+    cupsArrayAdd(conf, temp);
+  }
+
+  return conf;
+
+fail:
+  for (temp = (char *) cupsArrayFirst(conf);
+       temp;
+       temp = (char *) cupsArrayNext(conf))
+    free(temp);
+  cupsArrayDelete(conf);
+  return NULL;
+}
+
+
+/*
+ * 'cupsdCheckConfigurationAllowed()' - Check whether the new configuration
+ *                                      file can be installed
+ */
+
+int					/* O - 1 if allowed, 0 otherwise */
+cupsdCheckConfigurationAllowed(cupsd_client_t *con)
+{
+  int status = 0;
+  cups_file_t *fp;
+  cups_array_t *oldconf,
+    *newconf = NULL;
+  char *oldline,
+    *newline;
+
+  if (ConfigurationChangeRestriction == CUPSD_CONFRESTRICT_NONE)
+   /*
+    * Option checking disabled...
+    */
+    return (1);
+
+  if (ConfigurationChangeRestriction == CUPSD_CONFRESTRICT_ROOT &&
+      !strcmp (con->username, "root"))
+   /*
+    * This is requested by root and our configuration tells us to
+    * accept it.
+    */
+    return (1);
+
+ /*
+  * First read the current cupsd.conf...
+  */
+
+  if ((fp = cupsFileOpen (ConfigurationFile, "r")) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN, "Unable to open configuration file?!");
+    return (0);
+  }
+
+  oldconf = _cupsdGetBlacklistedConfLines(fp);
+  cupsFileClose(fp);
+  if (!oldconf)
+    return (0);
+
+ /*
+  * Now take a look at the proposed new cupsd.conf...
+  */
+
+  if ((fp = cupsFileOpen(con->filename, "r")) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN, "Unable to examine new config file");
+    goto fail;
+  }
+
+  newconf = _cupsdGetBlacklistedConfLines(fp);
+  cupsFileClose(fp);
+  if (!newconf)
+    goto fail;
+
+ /*
+  * Now compare the blacklisted directives in each.
+  */
+
+  status = 1;
+  for (oldline = (char *) cupsArrayFirst(oldconf);
+       oldline;
+       oldline = (char *) cupsArrayNext(oldconf))
+  {
+    for (newline = (char *) cupsArrayFirst(newconf);
+	 newline;
+	 newline = (char *) cupsArrayNext(newconf))
+      if (!strcmp (oldline, newline))
+	break;
+
+    if (newline == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+		      "Attempt to remove or change '%s' denied", oldline);
+      status = 0;
+      break;
+    }
+
+    cupsArrayRemove(newconf, newline);
+    free(newline);
+  }
+
+  if (status)
+  {
+   /*
+    * All the original directives are still present. Have any been added?
+    */
+
+    newline = (char *) cupsArrayFirst(newconf);
+    if (newline != NULL)
+    {
+      char *p;
+
+      cupsArrayRemove(newconf, newline);      
+
+      p = strchr (newline, ' ');
+      if (p)
+	*p = '\0';
+
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Attempt to add '%s' directive denied", newline);
+      free(newline);
+      status = 0;
+    }
+  }
+
+fail:
+  for (oldline = (char *) cupsArrayFirst(oldconf);
+       oldline;
+       oldline = (char *) cupsArrayNext(oldconf))
+    free(oldline);
+  cupsArrayDelete(oldconf);
+
+  if (newconf)
+  {
+    for (newline = (char *) cupsArrayFirst(newconf);
+	 newline;
+	 newline = (char *) cupsArrayNext(newconf))
+      free(newline);
+    cupsArrayDelete(newconf);
+  }
+
+  return (status);
+}
 
 /*
  * 'read_location()' - Read a <Location path> definition.
diff -up cups-1.3.7/scheduler/conf.h.CVE-2012-5519 cups-1.3.7/scheduler/conf.h
--- cups-1.3.7/scheduler/conf.h.CVE-2012-5519	2013-02-15 09:55:37.650201589 +0000
+++ cups-1.3.7/scheduler/conf.h	2013-02-15 09:55:37.719201968 +0000
@@ -59,6 +59,19 @@ typedef enum
 
 
 /*
+ * Configuration change restriction (CVE-2012-5519)
+ */
+
+typedef enum
+{
+  CUPSD_CONFRESTRICT_NONE,	/* No checking of PUT cupsd.conf */
+  CUPSD_CONFRESTRICT_ROOT,	/* Only allow root to change all opts */
+  CUPSD_CONFRESTRICT_ALL,	/* Restricted keywords not to be changed */
+} cupsd_confrestrict_t;
+
+
+
+/*
  * Globals...
  */
 
@@ -137,6 +150,8 @@ VAR int			ClassifyOverride	VALUE(0),
 					/* Allow overrides? */
 			ConfigFilePerm		VALUE(0640),
 					/* Permissions for config files */
+			ConfigurationChangeRestriction VALUE(CUPSD_CONFRESTRICT_ALL),
+					/* CVE-2012-5519 protection */
 			FatalErrors		VALUE(CUPSD_FATAL_CONFIG),
 					/* Which errors are fatal? */
 			LogFilePerm		VALUE(0644),
@@ -258,6 +273,7 @@ __attribute__ ((__format__ (__printf__,
 extern int	cupsdLogPage(cupsd_job_t *job, const char *page);
 extern int	cupsdLogRequest(cupsd_client_t *con, http_status_t code);
 extern int	cupsdReadConfiguration(void);
+extern int	cupsdCheckConfigurationAllowed(cupsd_client_t *con);
 
 
 /*