Blame SOURCES/cups-CVE-2018-4180.patch

5ee0f1
diff --git a/man/cups-files.conf.man.in b/man/cups-files.conf.man.in
5ee0f1
index e34d7c4..1d0f51d 100644
5ee0f1
--- a/man/cups-files.conf.man.in
5ee0f1
+++ b/man/cups-files.conf.man.in
5ee0f1
@@ -85,6 +85,11 @@ PageLog filename
5ee0f1
 PageLog syslog
5ee0f1
 .br
5ee0f1
 Specifies the page log filename.
5ee0f1
+.\"#PassEnv
5ee0f1
+.TP 5
5ee0f1
+\fBPassEnv \fIvariable \fR[ ... \fIvariable \fR]
5ee0f1
+Passes the specified environment variable(s) to child processes.
5ee0f1
+Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
5ee0f1
 .TP 5
5ee0f1
 Printcap
5ee0f1
 .TP 5
5ee0f1
@@ -121,6 +126,11 @@ Specifies the encryption key to use.
5ee0f1
 ServerRoot directory
5ee0f1
 .br
5ee0f1
 Specifies the directory where the server configuration files can be found.
5ee0f1
+.\"#SetEnv
5ee0f1
+.TP 5
5ee0f1
+\fBSetEnv \fIvariable value\fR
5ee0f1
+Set the specified environment variable to be passed to child processes.
5ee0f1
+Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
5ee0f1
 .TP 5
5ee0f1
 SyncOnClose Yes
5ee0f1
 .TP 5
5ee0f1
diff --git a/man/cupsd.conf.man.in b/man/cupsd.conf.man.in
5ee0f1
index 1a4f40a..583070e 100644
5ee0f1
--- a/man/cupsd.conf.man.in
5ee0f1
+++ b/man/cupsd.conf.man.in
5ee0f1
@@ -380,10 +380,6 @@ PageLogFormat format string
5ee0f1
 .br
5ee0f1
 Specifies the format of page log lines.
5ee0f1
 .TP 5
5ee0f1
-PassEnv variable [... variable]
5ee0f1
-.br
5ee0f1
-Passes the specified environment variable(s) to child processes.
5ee0f1
-.TP 5
5ee0f1
 <Policy name> ... </Policy>
5ee0f1
 .br
5ee0f1
 Specifies access control for the named policy.
5ee0f1
@@ -470,10 +466,6 @@ ServerTokens ProductOnly
5ee0f1
 Specifies what information is included in the Server header of HTTP
5ee0f1
 responses.
5ee0f1
 .TP 5
5ee0f1
-SetEnv variable value
5ee0f1
-.br
5ee0f1
-Set the specified environment variable to be passed to child processes.
5ee0f1
-.TP 5
5ee0f1
 SSLListen
5ee0f1
 .br
5ee0f1
 Listens on the specified address and port for encrypted connections.
5ee0f1
diff --git a/scheduler/conf.c b/scheduler/conf.c
5ee0f1
index f8732d4..ac1d024 100644
5ee0f1
--- a/scheduler/conf.c
5ee0f1
+++ b/scheduler/conf.c
5ee0f1
@@ -2935,13 +2935,10 @@ read_cupsd_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
 					/* Line from file */
5ee0f1
 			temp[HTTP_MAX_BUFFER],
5ee0f1
 					/* Temporary buffer for value */
5ee0f1
-			*value,		/* Pointer to value */
5ee0f1
-			*valueptr;	/* Pointer into value */
5ee0f1
+			*value;		/* Pointer to value */
5ee0f1
   int			valuelen;	/* Length of value */
5ee0f1
   http_addrlist_t	*addrlist,	/* Address list */
5ee0f1
 			*addr;		/* Current address */
5ee0f1
-  cups_file_t		*incfile;	/* Include file */
5ee0f1
-  char			incname[1024];	/* Include filename */
5ee0f1
 
5ee0f1
 
5ee0f1
  /*
5ee0f1
@@ -2956,28 +2953,7 @@ read_cupsd_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
     * Decode the directive...
5ee0f1
     */
5ee0f1
 
5ee0f1
-    if (!_cups_strcasecmp(line, "Include") && value)
5ee0f1
-    {
5ee0f1
-     /*
5ee0f1
-      * Include filename
5ee0f1
-      */
5ee0f1
-
5ee0f1
-      if (value[0] == '/')
5ee0f1
-        strlcpy(incname, value, sizeof(incname));
5ee0f1
-      else
5ee0f1
-        snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
5ee0f1
-
5ee0f1
-      if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
5ee0f1
-        cupsdLogMessage(CUPSD_LOG_ERROR,
5ee0f1
-	                "Unable to include config file \"%s\" - %s",
5ee0f1
-	                incname, strerror(errno));
5ee0f1
-      else
5ee0f1
-      {
5ee0f1
-        read_cupsd_conf(incfile);
5ee0f1
-	cupsFileClose(incfile);
5ee0f1
-      }
5ee0f1
-    }
5ee0f1
-    else if (!_cups_strcasecmp(line, "
5ee0f1
+    if (!_cups_strcasecmp(line, "
5ee0f1
     {
5ee0f1
      /*
5ee0f1
       * <Location path>
5ee0f1
@@ -3302,31 +3278,6 @@ read_cupsd_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
 	cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d.",
5ee0f1
                         value, linenum);
5ee0f1
     }
5ee0f1
-    else if (!_cups_strcasecmp(line, "PassEnv") && value)
5ee0f1
-    {
5ee0f1
-     /*
5ee0f1
-      * PassEnv variable [... variable]
5ee0f1
-      */
5ee0f1
-
5ee0f1
-      for (; *value;)
5ee0f1
-      {
5ee0f1
-        for (valuelen = 0; value[valuelen]; valuelen ++)
5ee0f1
-	  if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
5ee0f1
-	    break;
5ee0f1
-
5ee0f1
-        if (value[valuelen])
5ee0f1
-        {
5ee0f1
-	  value[valuelen] = '\0';
5ee0f1
-	  valuelen ++;
5ee0f1
-	}
5ee0f1
-
5ee0f1
-        cupsdSetEnv(value, NULL);
5ee0f1
-
5ee0f1
-        for (value += valuelen; *value; value ++)
5ee0f1
-	  if (!_cups_isspace(*value) || *value != ',')
5ee0f1
-	    break;
5ee0f1
-      }
5ee0f1
-    }
5ee0f1
     else if (!_cups_strcasecmp(line, "ServerAlias") && value)
5ee0f1
     {
5ee0f1
      /*
5ee0f1
@@ -3355,30 +3306,6 @@ read_cupsd_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
 	    break;
5ee0f1
       }
5ee0f1
     }
5ee0f1
-    else if (!_cups_strcasecmp(line, "SetEnv") && value)
5ee0f1
-    {
5ee0f1
-     /*
5ee0f1
-      * SetEnv variable value
5ee0f1
-      */
5ee0f1
-
5ee0f1
-      for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
5ee0f1
-
5ee0f1
-      if (*valueptr)
5ee0f1
-      {
5ee0f1
-       /*
5ee0f1
-        * Found a value...
5ee0f1
-	*/
5ee0f1
-
5ee0f1
-        while (isspace(*valueptr & 255))
5ee0f1
-	  *valueptr++ = '\0';
5ee0f1
-
5ee0f1
-        cupsdSetEnv(value, valueptr);
5ee0f1
-      }
5ee0f1
-      else
5ee0f1
-        cupsdLogMessage(CUPSD_LOG_ERROR,
5ee0f1
-	                "Missing value for SetEnv directive on line %d.",
5ee0f1
-	                linenum);
5ee0f1
-    }
5ee0f1
 #ifdef HAVE_SSL
5ee0f1
     else if (!_cups_strcasecmp(line, "SSLOptions"))
5ee0f1
     {
5ee0f1
@@ -3448,6 +3375,7 @@ read_cupsd_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
              !_cups_strcasecmp(line, "LogFilePerm") ||
5ee0f1
              !_cups_strcasecmp(line, "LPDConfigFile") ||
5ee0f1
              !_cups_strcasecmp(line, "PageLog") ||
5ee0f1
+             !_cups_strcasecmp(line, "PassEnv") ||
5ee0f1
              !_cups_strcasecmp(line, "Printcap") ||
5ee0f1
              !_cups_strcasecmp(line, "PrintcapFormat") ||
5ee0f1
              !_cups_strcasecmp(line, "RemoteRoot") ||
5ee0f1
@@ -3456,6 +3384,7 @@ read_cupsd_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
              !_cups_strcasecmp(line, "ServerCertificate") ||
5ee0f1
              !_cups_strcasecmp(line, "ServerKey") ||
5ee0f1
              !_cups_strcasecmp(line, "ServerRoot") ||
5ee0f1
+             !_cups_strcasecmp(line, "SetEnv") ||
5ee0f1
              !_cups_strcasecmp(line, "SMBConfigFile") ||
5ee0f1
              !_cups_strcasecmp(line, "StateDir") ||
5ee0f1
              !_cups_strcasecmp(line, "SystemGroup") ||
5ee0f1
@@ -3485,11 +3414,51 @@ read_cupsd_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
 static int				/* O - 1 on success, 0 on failure */
5ee0f1
 read_cups_files_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
 {
5ee0f1
-  int		linenum;		/* Current line number */
5ee0f1
+  int		i,			/* Looping var */
5ee0f1
+		linenum;		/* Current line number */
5ee0f1
   char		line[HTTP_MAX_BUFFER],	/* Line from file */
5ee0f1
 		*value;			/* Value from line */
5ee0f1
   struct group	*group;			/* Group */
5ee0f1
 
5ee0f1
+  static const char * const prohibited_env[] =
5ee0f1
+  {					/* Prohibited environment variables */
5ee0f1
+    "APPLE_LANGUAGE",
5ee0f1
+    "AUTH_DOMAIN",
5ee0f1
+    "AUTH_INFO_REQUIRED",
5ee0f1
+    "AUTH_NEGOTIATE",
5ee0f1
+    "AUTH_PASSWORD",
5ee0f1
+    "AUTH_UID",
5ee0f1
+    "AUTH_USERNAME",
5ee0f1
+    "CHARSET",
5ee0f1
+    "CLASS",
5ee0f1
+    "CLASSIFICATION",
5ee0f1
+    "CONTENT_TYPE",
5ee0f1
+    "CUPS_CACHEDIR",
5ee0f1
+    "CUPS_DATADIR",
5ee0f1
+    "CUPS_DOCROOT",
5ee0f1
+    "CUPS_FILETYPE",
5ee0f1
+    "CUPS_FONTPATH",
5ee0f1
+    "CUPS_MAX_MESSAGE",
5ee0f1
+    "CUPS_REQUESTROOT",
5ee0f1
+    "CUPS_SERVERBIN",
5ee0f1
+    "CUPS_SERVERROOT",
5ee0f1
+    "CUPS_STATEDIR",
5ee0f1
+    "DEVICE_URI",
5ee0f1
+    "FINAL_CONTENT_TYPE",
5ee0f1
+    "HOME",
5ee0f1
+    "LANG",
5ee0f1
+    "PPD",
5ee0f1
+    "PRINTER",
5ee0f1
+    "PRINTER_INFO",
5ee0f1
+    "PRINTER_LOCATION",
5ee0f1
+    "PRINTER_STATE_REASONS",
5ee0f1
+    "RIP_CACHE",
5ee0f1
+    "SERVER_ADMIN",
5ee0f1
+    "SOFTWARE",
5ee0f1
+    "TMPDIR",
5ee0f1
+    "USER"
5ee0f1
+  };
5ee0f1
+
5ee0f1
 
5ee0f1
  /*
5ee0f1
   * Loop through each line in the file...
5ee0f1
@@ -3526,6 +3495,87 @@ read_cups_files_conf(cups_file_t *fp)	/* I - File to read from */
5ee0f1
 	}
5ee0f1
       }
5ee0f1
     }
5ee0f1
+    else if (!_cups_strcasecmp(line, "PassEnv") && value)
5ee0f1
+    {
5ee0f1
+     /*
5ee0f1
+      * PassEnv variable [... variable]
5ee0f1
+      */
5ee0f1
+
5ee0f1
+      int valuelen;			/* Length of variable name */
5ee0f1
+
5ee0f1
+      for (; *value;)
5ee0f1
+      {
5ee0f1
+        for (valuelen = 0; value[valuelen]; valuelen ++)
5ee0f1
+	        if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
5ee0f1
+	          break;
5ee0f1
+
5ee0f1
+        if (value[valuelen])
5ee0f1
+        {
5ee0f1
+	        value[valuelen] = '\0';
5ee0f1
+	        valuelen ++;
5ee0f1
+	      }
5ee0f1
+
5ee0f1
+        for (i = 0; i < (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])); i ++)
5ee0f1
+        {
5ee0f1
+          if (!strcmp(value, prohibited_env[i]))
5ee0f1
+          {
5ee0f1
+	          cupsdLogMessage(CUPSD_LOG_ERROR, "Environment variable \"%s\" cannot be passed through on line %d of %s.", value, linenum, CupsFilesFile);
5ee0f1
+
5ee0f1
+            if (FatalErrors & CUPSD_FATAL_CONFIG)
5ee0f1
+              return (0);
5ee0f1
+            else
5ee0f1
+              break;
5ee0f1
+          }
5ee0f1
+	      }
5ee0f1
+
5ee0f1
+        if (i >= (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])))
5ee0f1
+          cupsdSetEnv(value, NULL);
5ee0f1
+
5ee0f1
+        for (value += valuelen; *value; value ++)
5ee0f1
+	        if (!_cups_isspace(*value) || *value != ',')
5ee0f1
+	          break;
5ee0f1
+      }
5ee0f1
+    }
5ee0f1
+    else if (!_cups_strcasecmp(line, "SetEnv") && value)
5ee0f1
+    {
5ee0f1
+      /*
5ee0f1
+      * SetEnv variable value
5ee0f1
+      */
5ee0f1
+
5ee0f1
+      char *valueptr;			/* Pointer to environment variable value */
5ee0f1
+
5ee0f1
+      for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
5ee0f1
+
5ee0f1
+      if (*valueptr)
5ee0f1
+      {
5ee0f1
+       /*
5ee0f1
+        * Found a value...
5ee0f1
+	      */
5ee0f1
+
5ee0f1
+        while (isspace(*valueptr & 255))
5ee0f1
+	        *valueptr++ = '\0';
5ee0f1
+
5ee0f1
+        for (i = 0; i < (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])); i ++)
5ee0f1
+        {
5ee0f1
+          if (!strcmp(value, prohibited_env[i]))
5ee0f1
+          {
5ee0f1
+	          cupsdLogMessage(CUPSD_LOG_ERROR, "Environment variable \"%s\" cannot be set  on line %d of %s.", value, linenum, CupsFilesFile);
5ee0f1
+
5ee0f1
+            if (FatalErrors & CUPSD_FATAL_CONFIG)
5ee0f1
+              return (0);
5ee0f1
+            else
5ee0f1
+              break;
5ee0f1
+          }
5ee0f1
+	      }
5ee0f1
+
5ee0f1
+        if (i >= (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])))
5ee0f1
+	        cupsdSetEnv(value, valueptr);
5ee0f1
+      }
5ee0f1
+      else
5ee0f1
+        cupsdLogMessage(CUPSD_LOG_ERROR,
5ee0f1
+	                "Missing value for SetEnv directive on line %d of %s.",
5ee0f1
+	                linenum, ConfigurationFile);
5ee0f1
+    }
5ee0f1
     else if (!_cups_strcasecmp(line, "PrintcapFormat") && value)
5ee0f1
     {
5ee0f1
      /*
5ee0f1
diff --git a/scheduler/job.c b/scheduler/job.c
5ee0f1
index 48cc35d..0e1bca3 100644
5ee0f1
--- a/scheduler/job.c
5ee0f1
+++ b/scheduler/job.c
5ee0f1
@@ -4761,6 +4761,18 @@ start_job(cupsd_job_t     *job,		/* I - Job ID */
5ee0f1
   job->status  = 0;
5ee0f1
   job->profile = cupsdCreateProfile(job->id);
5ee0f1
 
5ee0f1
+  #ifdef HAVE_SANDBOX_H
5ee0f1
+    if (!job->profile)
5ee0f1
+    {
5ee0f1
+    /*
5ee0f1
+      * Failure to create the sandbox profile means something really bad has
5ee0f1
+      * happened and we need to shutdown immediately.
5ee0f1
+      */
5ee0f1
+
5ee0f1
+      return;
5ee0f1
+    }
5ee0f1
+  #endif /* HAVE_SANDBOX_H */
5ee0f1
+
5ee0f1
  /*
5ee0f1
   * Create the status pipes and buffer...
5ee0f1
   */
5ee0f1
diff --git a/scheduler/process.c b/scheduler/process.c
5ee0f1
index 1782064..b460838 100644
5ee0f1
--- a/scheduler/process.c
5ee0f1
+++ b/scheduler/process.c
5ee0f1
@@ -94,10 +94,14 @@ cupsdCreateProfile(int job_id)		/* I - Job ID or 0 for none */
5ee0f1
 
5ee0f1
   if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL)
5ee0f1
   {
5ee0f1
+    /*
5ee0f1
+    * This should never happen, and is fatal when sandboxing is enabled.
5ee0f1
+    */
5ee0f1
+
5ee0f1
     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
5ee0f1
                     job_id);
5ee0f1
-    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s",
5ee0f1
-                    strerror(errno));
5ee0f1
+    cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to create security profile: %s", strerror(errno));
5ee0f1
+    kill(getpid(), SIGTERM);
5ee0f1
     return (NULL);
5ee0f1
   }
5ee0f1
 
5ee0f1
diff --git a/scheduler/server.c b/scheduler/server.c
5ee0f1
index a5a31c5..7a34891 100644
5ee0f1
--- a/scheduler/server.c
5ee0f1
+++ b/scheduler/server.c
5ee0f1
@@ -44,17 +44,29 @@ static int		started = 0;	/* Did we start the server already? */
5ee0f1
 void
5ee0f1
 cupsdStartServer(void)
5ee0f1
 {
5ee0f1
- /*
5ee0f1
-  * Start color management (as needed)...
5ee0f1
+  /*
5ee0f1
+  * Create the default security profile...
5ee0f1
   */
5ee0f1
 
5ee0f1
-  cupsdStartColor();
5ee0f1
+  DefaultProfile = cupsdCreateProfile(0);
5ee0f1
+
5ee0f1
+  #ifdef HAVE_SANDBOX_H
5ee0f1
+    if (!DefaultProfile)
5ee0f1
+    {
5ee0f1
+    /*
5ee0f1
+      * Failure to create the sandbox profile means something really bad has
5ee0f1
+      * happened and we need to shutdown immediately.
5ee0f1
+      */
5ee0f1
+
5ee0f1
+      return;
5ee0f1
+    }
5ee0f1
+  #endif /* HAVE_SANDBOX_H */
5ee0f1
 
5ee0f1
  /*
5ee0f1
-  * Create the default security profile...
5ee0f1
+  * Start color management (as needed)...
5ee0f1
   */
5ee0f1
 
5ee0f1
-  DefaultProfile = cupsdCreateProfile(0);
5ee0f1
+  cupsdStartColor();
5ee0f1
 
5ee0f1
  /*
5ee0f1
   * Startup all the networking stuff...