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