Hello community, here is the log from the commit of package cups for openSUSE:Factory checked in at 2014-02-19 09:09:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cups (Old) and /work/SRC/openSUSE:Factory/.cups.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cups" Changes: -------- --- /work/SRC/openSUSE:Factory/cups/cups.changes 2014-02-07 10:25:42.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.cups.new/cups.changes 2014-02-19 09:09:45.000000000 +0100 @@ -1,0 +2,54 @@ +Wed Feb 12 11:53:45 CET 2014 - [email protected] + +- Added Begin/End comments in scriptlets for RPM macros + so that it is easier to see in the "rpm -q --scripts cups" + output what each RPM macro actually does. + +------------------------------------------------------------------- +Wed Feb 12 10:30:42 CET 2014 - [email protected] + +- Clean up how cupsd is launched (via SysVinit or systemd) + by maintaining strictly separated sections in cups.spec: + Either for launching cupsd via systemd (if have_systemd is set) + or for launching cupsd via SysVinit (if have_systemd is not set). + SysVinit support cannot be removed because CUPS 1.5.4 + is provided for SLE11 in the OBS devel project "Printing". + +------------------------------------------------------------------- +Wed Feb 5 14:04:42 CET 2014 - [email protected] + +- cups-1.5.4-CVE-2012-5519.patch adds better default protection + against misuse of privileges by normal users who have been + specifically allowed by root to do cupsd configuration changes + (CUPS STR#4223 CVE-2012-5519 Novell/Suse Bugzilla bnc#789566). + The new ConfigurationChangeRestriction cupsd.conf directive + specifies the level of restriction for cupsd.conf changes + that happen via HTTP/IPP requests to the running cupsd + (e.g. via CUPS web interface or via the cupsctl command). + By default certain cupsd.conf directives that deal with + filenames, paths, and users can no longer be changed via + requests to the running cupsd but only by manual editing + the cupsd.conf file and its default file permissions + permit only root to write the cupsd.conf file. + Those directives are: ConfigurationChangeRestriction, + AccessLog, BrowseLDAPCACertFile, CacheDir, ConfigFilePerm, + DataDir, DocumentRoot, ErrorLog, FatalErrors, FileDevice, + FontPath, Group, JobPrivateAccess, JobPrivateValues, + LogFilePerm, PageLog, Printcap, PrintcapFormat, PrintcapGUI, + RemoteRoot, RequestRoot, ServerBin, ServerCertificate, + ServerKey, ServerRoot, StateDir, SubscriptionPrivateAccess, + SubscriptionPrivateValues, SystemGroup, SystemGroupAuthKey, + TempDir, User, WebInterface. +- The default group of users who are allowed to do cupsd + configuration changes via requests to the running cupsd + (i.e. the SystemGroup directive in cupsd.conf) is set + to 'root' only. +- In this context a general security advice: + When root allows normal users to do system administration tasks + (in particular when root allows normal users to administer + system processes - i.e. processes that run as root), then + this or that kind of privilege escalation will be possible. + Only trustworthy users who do not misuse their privileges + may get allowed to do specific system administration tasks. + +------------------------------------------------------------------- New: ---- cups-1.5.4-CVE-2012-5519.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cups.spec ++++++ --- /var/tmp/diff_new_pack.UQTKFR/_old 2014-02-19 09:09:46.000000000 +0100 +++ /var/tmp/diff_new_pack.UQTKFR/_new 2014-02-19 09:09:46.000000000 +0100 @@ -45,7 +45,7 @@ BuildRequires: pkgconfig(systemd) %{?systemd_requires} %define have_systemd 1 -#may not be defined in older systemd macros.. +# may not be defined in older systemd macros.. %{!?_tmpfilesdir: %global _tmpfilesdir /usr/lib/tmpfiles.d } %endif # The "BuildRequires: poppler-tools" installs /usr/bin/pdftops for the @@ -177,7 +177,7 @@ # http://lists.opensuse.org/opensuse-factory/2013-01/msg00578.html Patch108: cups-move-everything-to-run.patch # Patch109 fixes STR #4190: Send-Document failure ignored -#(also applies to client-error-not-authorized) +# (also applies to client-error-not-authorized) Patch109: str4190.patch # Patch110 avoids any possible busy loop in cups-polld in case of unusual issues # by sleeping interval seconds see https://bugzilla.novell.com/show_bug.cgi?id=828228 @@ -192,6 +192,10 @@ # see https://bugzilla.novell.com/show_bug.cgi?id=857372#c61 # Patch111 must be applied on top of Patch105. Patch112: cups-0003-systemd-secure-cups.service-unit-file.patch +# Patch113 adds protection against privilege escalation by non-root users +# who have been allowed by root to do CUPS configuration changes +# (CUPS STR#4223 CVE-2012-5519 Novell/Suse Bugzilla bnc#789566): +Patch113: cups-1.5.4-CVE-2012-5519.patch # Install into this non-root directory (required when norootforbuild is used): BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -348,6 +352,10 @@ # see https://bugzilla.novell.com/show_bug.cgi?id=857372#c61 # Patch111 must be applied on top of Patch105. %patch112 +# Patch113 adds protection against privilege escalation by non-root users +# who have been allowed by root to do CUPS configuration changes +# (CUPS STR#4223 CVE-2012-5519 Novell/Suse Bugzilla bnc#789566): +%patch113 %build # Disable SILENT run of make so that make runs verbose as usual: @@ -376,6 +384,7 @@ --with-docdir=%{_datadir}/cups/webcontent \ --with-cups-user=lp \ --with-cups-group=lp \ + --with-system-groups=root \ --enable-debug \ --enable-relro \ --enable-gssapi \ @@ -395,8 +404,7 @@ make %{?_smp_mflags} CXX=g++ %install -make BUILDROOT=$RPM_BUILD_ROOT install -install -d -m755 $RPM_BUILD_ROOT/etc/init.d +make BUILDROOT=%{buildroot} install # Use CUPS' own fonts (i.e. make CUPS work again in compliance with upstream). # In ancient times (see the RPM changelog entry dated "Thu Aug 16 17:05:19 CEST 2001") # there was the general opinion it would be a great idea to deviate from CUPS upstream @@ -416,48 +424,41 @@ # and the only way out is to move CUPS' own fonts to an artificial # surrogate directory /usr/share/cups/CUPSfonts and have the # symbolic link /usr/share/cups/fonts -> /usr/share/cups/CUPSfonts: -pushd $RPM_BUILD_ROOT/usr/share/cups/ +pushd %{buildroot}/usr/share/cups/ mv fonts CUPSfonts && ln -s CUPSfonts fonts popd -# Source101: cups.init -install -m755 %{SOURCE101} $RPM_BUILD_ROOT/etc/init.d/cups -ln -sf ../../etc/init.d/cups $RPM_BUILD_ROOT/usr/sbin/rccups -%if %suse_version > 1220 -sed -i -e 's|/var/run|/run|g' $RPM_BUILD_ROOT/etc/init.d/cups -sed -i -e 's|/var/lock|/run/lock|g' $RPM_BUILD_ROOT/etc/init.d/cups -%endif # Source103: cups.sysconfig -install -d -m755 $RPM_BUILD_ROOT/var/adm/fillup-templates -install -m 644 %{SOURCE103} $RPM_BUILD_ROOT/var/adm/fillup-templates/sysconfig.cups +install -d -m755 %{buildroot}/var/adm/fillup-templates +install -m 644 %{SOURCE103} %{buildroot}/var/adm/fillup-templates/sysconfig.cups # Make directory for ssl files: -mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/cups/ssl +mkdir -p %{buildroot}%{_sysconfdir}/cups/ssl # Add a client.conf as template (Source108: cups-client.conf): -install -m644 %{SOURCE108} $RPM_BUILD_ROOT%{_sysconfdir}/cups/client.conf +install -m644 %{SOURCE108} %{buildroot}%{_sysconfdir}/cups/client.conf %if %suse_version > 1220 -sed -i -e 's|/var/run|/run|g' $RPM_BUILD_ROOT%{_sysconfdir}/cups/client.conf +sed -i -e 's|/var/run|/run|g' %{buildroot}%{_sysconfdir}/cups/client.conf %endif # Source104: cups.xinetd -mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/xinetd.d -install -m 644 -D %{SOURCE104} $RPM_BUILD_ROOT%{_sysconfdir}/xinetd.d/cups-lpd +mkdir -p %{buildroot}%{_sysconfdir}/xinetd.d +install -m 644 -D %{SOURCE104} %{buildroot}%{_sysconfdir}/xinetd.d/cups-lpd # Make the libraries accessible also via generic named links: -ln -sf libcupsimage.so.2 $RPM_BUILD_ROOT%{_libdir}/libcupsimage.so -ln -sf libcups.so.2 $RPM_BUILD_ROOT%{_libdir}/libcups.so +ln -sf libcupsimage.so.2 %{buildroot}%{_libdir}/libcupsimage.so +ln -sf libcups.so.2 %{buildroot}%{_libdir}/libcups.so # Add missing usual directories: -install -d -m755 $RPM_BUILD_ROOT%{_datadir}/cups/drivers -install -d -m755 $RPM_BUILD_ROOT/var/cache/cups +install -d -m755 %{buildroot}%{_datadir}/cups/drivers +install -d -m755 %{buildroot}/var/cache/cups # Add conf/pam.suse regarding support for PAM (see Patch100: cups-pam.diff): -install -m 644 -D conf/pam.suse $RPM_BUILD_ROOT/etc/pam.d/cups +install -m 644 -D conf/pam.suse %{buildroot}/etc/pam.d/cups # Add missing usual documentation: -install -d -m755 $RPM_BUILD_ROOT/%{_defaultdocdir}/cups +install -d -m755 %{buildroot}/%{_defaultdocdir}/cups for f in CHANGES*.txt CREDITS.txt INSTALL.txt LICENSE.txt README.txt -do install -m 644 "$f" $RPM_BUILD_ROOT%{_defaultdocdir}/cups/ +do install -m 644 "$f" %{buildroot}%{_defaultdocdir}/cups/ done # Source102: postscript.ppd.bz2 -bzip2 -cd < %{SOURCE102} > $RPM_BUILD_ROOT%{_datadir}/cups/model/Postscript.ppd +bzip2 -cd < %{SOURCE102} > %{buildroot}%{_datadir}/cups/model/Postscript.ppd # Source105: PSLEVEL1.PPD.bz2 -bzip2 -cd < %{SOURCE105} > $RPM_BUILD_ROOT%{_datadir}/cups/model/Postscript-level1.ppd +bzip2 -cd < %{SOURCE105} > %{buildroot}%{_datadir}/cups/model/Postscript-level1.ppd # Source106: PSLEVEL2.PPD.bz2 -bzip2 -cd < %{SOURCE106} > $RPM_BUILD_ROOT%{_datadir}/cups/model/Postscript-level2.ppd +bzip2 -cd < %{SOURCE106} > %{buildroot}%{_datadir}/cups/model/Postscript-level2.ppd find %{buildroot}/usr/share/cups/model -name "*.ppd" | while read FILE do # Change default paper size from Letter to A4 if possible # https://bugzilla.novell.com/show_bug.cgi?id=suse30662 @@ -469,42 +470,65 @@ gzip -9 "$FILE" done # Add files for desktop menu: -rm -f $RPM_BUILD_ROOT/usr/share/applications/cups.desktop +rm -f %{buildroot}/usr/share/applications/cups.desktop %suse_update_desktop_file -i cups PrintingUtility 2>/dev/null -mkdir $RPM_BUILD_ROOT/usr/share/pixmaps -install -m 644 $RPM_BUILD_ROOT/usr/share/icons/hicolor/64x64/apps/cups.png $RPM_BUILD_ROOT/usr/share/pixmaps -rm -rf $RPM_BUILD_ROOT/usr/share/icons -# Norwegian is "nb", "zh" is probably "zh_CN" -mv $RPM_BUILD_ROOT/usr/share/locale/{no,nb} -mv $RPM_BUILD_ROOT/usr/share/locale/{zh,zh_CN} +mkdir %{buildroot}/usr/share/pixmaps +install -m 644 %{buildroot}/usr/share/icons/hicolor/64x64/apps/cups.png %{buildroot}/usr/share/pixmaps +rm -rf %{buildroot}/usr/share/icons +# Norwegian is "nb", "zh" is probably "zh_CN": +mv %{buildroot}/usr/share/locale/{no,nb} +mv %{buildroot}/usr/share/locale/{zh,zh_CN} # Save /etc/cups/cupsd.conf and /etc/cups/cupsd.conf.default from becoming hardlinked # via the fdupes run below, see https://bugzilla.novell.com/show_bug.cgi?id=773971 # by making their content different and at the same time fix the misleading comment. # Intentionally let the build fail if 'grep' does not find what 'sed' should change # because if upstream changed it 'sed' would silently no longer change the files # so that fdupes would make /etc/cups/cupsd.conf and /etc/cups/cupsd.conf.default hardlinked: -grep -q '^# Sample configuration ' $RPM_BUILD_ROOT/%{_sysconfdir}/cups/cupsd.conf -sed -i -e 's/^# Sample configuration /# Configuration /' $RPM_BUILD_ROOT/%{_sysconfdir}/cups/cupsd.conf -grep -q '^# Sample configuration ' $RPM_BUILD_ROOT/%{_sysconfdir}/cups/cupsd.conf.default -sed -i -e 's/^# Sample configuration /# Default configuration /' $RPM_BUILD_ROOT/%{_sysconfdir}/cups/cupsd.conf.default -# systemd stuff: +grep -q '^# Sample configuration ' %{buildroot}/%{_sysconfdir}/cups/cupsd.conf +sed -i -e 's/^# Sample configuration /# Configuration /' %{buildroot}/%{_sysconfdir}/cups/cupsd.conf +grep -q '^# Sample configuration ' %{buildroot}/%{_sysconfdir}/cups/cupsd.conf.default +sed -i -e 's/^# Sample configuration /# Default configuration /' %{buildroot}/%{_sysconfdir}/cups/cupsd.conf.default +# Begin how cupsd is launched (via SysVinit or systemd): %if 0%{?have_systemd} -# move the installed cups.socket and cups.path into a documentation directory +# Begin launch cupsd via systemd: +# See http://en.opensuse.org/openSUSE:Systemd_packaging_guidelines +# Move the installed cups.socket and cups.path into a documentation directory # so that experienced admins can make their own individual systemd unit files # for socket activation and/or path activation as they need it for their particular cases # see https://bugzilla.novell.com/show_bug.cgi?id=857372#c61 -mkdir $RPM_BUILD_ROOT/%{_defaultdocdir}/cups/systemd -mv $RPM_BUILD_ROOT/%{_unitdir}/cups.path $RPM_BUILD_ROOT/%{_defaultdocdir}/cups/systemd/cups.path -mv $RPM_BUILD_ROOT/%{_unitdir}/cups.socket $RPM_BUILD_ROOT/%{_defaultdocdir}/cups/systemd/cups.socket -# install /usr/lib/tmpfiles.d/cups.conf -mkdir -p ${RPM_BUILD_ROOT}%{_tmpfilesdir} -cat > ${RPM_BUILD_ROOT}%{_tmpfilesdir}/cups.conf <<EOF +mkdir %{buildroot}/%{_defaultdocdir}/cups/systemd +mv %{buildroot}/%{_unitdir}/cups.path %{buildroot}/%{_defaultdocdir}/cups/systemd/cups.path +mv %{buildroot}/%{_unitdir}/cups.socket %{buildroot}/%{_defaultdocdir}/cups/systemd/cups.socket +# Install /usr/lib/tmpfiles.d/cups.conf +mkdir -p %{buildroot}%{_tmpfilesdir} +cat > %{buildroot}%{_tmpfilesdir}/cups.conf <<EOF # See tmpfiles.d(5) for details d /run/cups 0755 root lp - d /run/cups/certs 0511 lp sys - d /var/spool/cups/tmp - - - 30d EOF +# Provide SUSE policy symlink /usr/sbin/rcFOO -> /etc/init.d/FOO +# /usr/sbin/service exists only since openSUSE 12.3: +%if 0%{?suse_version} > 1220 +ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rccups +%else +ln -s /sbin/service %{buildroot}%{_sbindir}/rccups +%endif +# End launch cupsd via systemd +%else +# Begin launch cupsd via SysVinit: +# Source101: cups.init +install -d -m755 %{buildroot}/etc/init.d +install -m755 %{SOURCE101} %{buildroot}/etc/init.d/cups +ln -sf ../../etc/init.d/cups %{buildroot}/usr/sbin/rccups +%if %suse_version > 1220 +# Adapt init script according to Patch108 that moves everything to /run +sed -i -e 's|/var/run|/run|g' %{buildroot}/etc/init.d/cups +sed -i -e 's|/var/lock|/run/lock|g' %{buildroot}/etc/init.d/cups +%endif +# End launch cupsd via SysVinit %endif +# End how cupsd is launched (via SysVinit or systemd) # Run fdupes: # The RPM macro fdupes runs /usr/bin/fdupes that links files with identical content. # Never run fdupes carelessly over the whole buildroot directory @@ -516,42 +540,79 @@ # so that fdupes can only run for specific directories where linking files is safe. # Using fdupes -s, which will create symlinks that are easier to grasp for rpm and # rpmlint will give a "dangling symlink" error if the file and link ended up in different packages: -%fdupes -s $RPM_BUILD_ROOT/%{_datadir}/cups +%fdupes -s %{buildroot}/%{_datadir}/cups %pre +# Use a real bash script with an explicit "exit 0" at the end to be by default fail safe +# an explicit "exit 1" must be use to enforce package install/upgrade/erase failure where needed +# see the "Shared_libraries" section in http://en.opensuse.org/openSUSE:Packaging_scriptlet_snippets /usr/sbin/groupadd -g 71 -o -r ntadmin 2>/dev/null || : %if 0%{?have_systemd} -%service_add_pre cups.service cups.socket cups.path +# Begin service_add_pre cups.service +%service_add_pre cups.service +# End service_add_pre cups.service %endif exit 0 %post -%{fillup_and_insserv -ny cups cups} +# Use a real bash script with an explicit "exit 0" at the end to be by default fail safe +# an explicit "exit 1" must be use to enforce package install/upgrade/erase failure where needed +# see the "Shared_libraries" section in http://en.opensuse.org/openSUSE:Packaging_scriptlet_snippets %if 0%{?have_systemd} -%service_add_post cups.service cups.socket cups.path +# Begin service_add_post cups.service +%service_add_post cups.service +# End service_add_post cups.service +%else +# Begin fillup_and_insserv -ny cups cups +%{fillup_and_insserv -ny cups cups} +# End fillup_and_insserv -ny cups cups %endif exit 0 %preun -%stop_on_removal cups +# Use a real bash script with an explicit "exit 0" at the end to be by default fail safe +# an explicit "exit 1" must be use to enforce package install/upgrade/erase failure where needed +# see the "Shared_libraries" section in http://en.opensuse.org/openSUSE:Packaging_scriptlet_snippets %if 0%{?have_systemd} -%service_del_preun cups.service cups.socket cups.path +# Begin service_del_preun cups.service +%service_del_preun cups.service +# End service_del_preun cups.service +%else +# Begin stop_on_removal cups +%stop_on_removal cups +# End stop_on_removal cups %endif exit 0 %postun +# Use a real bash script with an explicit "exit 0" at the end to be by default fail safe +# an explicit "exit 1" must be use to enforce package install/upgrade/erase failure where needed +# see the "Shared_libraries" section in http://en.opensuse.org/openSUSE:Packaging_scriptlet_snippets +%if 0%{?have_systemd} +# Begin service_del_postun cups.service +%service_del_postun cups.service +# End service_del_postun cups.service +%else +# Begin restart_on_update cups %restart_on_update cups +# End restart_on_update cups +# Begin insserv_cleanup %{insserv_cleanup} -%if 0%{?have_systemd} -%service_del_postun cups.service cups.socket cups.path +# End insserv_cleanup %endif exit 0 %post libs +# Use a real bash script with an explicit "exit 0" at the end to be by default fail safe +# an explicit "exit 1" must be use to enforce package install/upgrade/erase failure where needed +# see the "Shared_libraries" section in http://en.opensuse.org/openSUSE:Packaging_scriptlet_snippets /sbin/ldconfig exit 0 %postun libs +# Use a real bash script with an explicit "exit 0" at the end to be by default fail safe +# an explicit "exit 1" must be use to enforce package install/upgrade/erase failure where needed +# see the "Shared_libraries" section in http://en.opensuse.org/openSUSE:Packaging_scriptlet_snippets /sbin/ldconfig exit 0 @@ -572,12 +633,17 @@ %config(noreplace) %attr(640,root,lp) %{_sysconfdir}/cups/snmp.conf %config(noreplace) %attr(755,lp,lp) %{_sysconfdir}/cups/interfaces %config(noreplace) %{_sysconfdir}/xinetd.d/cups-lpd -%config %attr(0755,root,root) %{_sysconfdir}/init.d/cups %config %{_sysconfdir}/pam.d/cups %config %{_sysconfdir}/dbus-1/system.d/cups.conf %dir %attr(700,root,lp) %{_sysconfdir}/cups/ssl %dir %attr(755,root,lp) %{_sysconfdir}/cups/ppd /var/adm/fillup-templates/sysconfig.cups +%if 0%{?have_systemd} +%{_unitdir}/cups.service +%{_tmpfilesdir}/cups.conf +%else +%config %attr(0755,root,root) %{_sysconfdir}/init.d/cups +%endif %{_bindir}/cupstestppd %{_sbindir}/cupsaddsmb %{_sbindir}/cupsctl @@ -661,10 +727,6 @@ %doc %{_mandir}/man8/cupsfilter.8.gz %{_datadir}/cups/ %exclude %{_datadir}/cups/ppdc/ -%if 0%{?have_systemd} -%{_unitdir}/cups.service -%{_tmpfilesdir}/cups.conf -%endif %files client # Set explicite owner, group, and permissions for lppasswd ++++++ cups-1.5.4-CVE-2012-5519.patch ++++++ --- doc/help/ref-cupsd-conf.html.in.orig 2012-01-30 22:40:21.000000000 +0100 +++ doc/help/ref-cupsd-conf.html.in 2014-02-05 14:13:23.000000000 +0100 @@ -917,6 +917,28 @@ ConfigFilePerm 0640 </BLOCKQUOTE> +<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> --- man/cupsctl.man.orig 2011-01-11 04:04:04.000000000 +0100 +++ man/cupsctl.man 2014-02-05 14:15:23.000000000 +0100 @@ -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 --- man/cupsd.conf.man.in.orig 2011-05-18 23:33:35.000000000 +0200 +++ man/cupsd.conf.man.in 2014-02-05 14:16:58.000000000 +0100 @@ -238,6 +238,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. --- scheduler/client.c.orig 2012-03-07 07:05:39.000000000 +0100 +++ scheduler/client.c 2014-02-05 14:32:49.000000000 +0100 @@ -1685,13 +1685,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... */ cupsdLogMessage(CUPSD_LOG_ERROR, @@ -3827,6 +3824,8 @@ install_conf_file(cupsd_client_t *con) / char buffer[16384]; /* Copy buffer */ ssize_t bytes; /* Number of bytes */ + if (!cupsdCheckConfigurationAllowed (con)) + return (HTTP_FORBIDDEN); /* * Open the request file... --- scheduler/conf.h.orig 2011-04-22 19:47:03.000000000 +0200 +++ scheduler/conf.h 2014-02-05 14:44:49.000000000 +0100 @@ -92,6 +92,18 @@ typedef struct /* + * 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... */ @@ -165,6 +177,8 @@ VAR int ClassifyOverride VALUE(0), /* Allow overrides? */ ConfigFilePerm VALUE(0640), /* Permissions for config files */ + ConfigurationChangeRestriction VALUE(CUPSD_CONFRESTRICT_ALL), + /* CVE-2012-5519 protection */ LogDebugHistory VALUE(200), /* Amount of automatic debug history */ FatalErrors VALUE(CUPSD_FATAL_CONFIG), @@ -291,6 +305,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); extern int cupsdWriteErrorLog(int level, const char *message); --- scheduler/conf.c.orig 2011-11-16 16:28:11.000000000 +0100 +++ scheduler/conf.c 2014-02-05 15:03:28.000000000 +0100 @@ -3196,6 +3196,22 @@ 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); + return (0); + } + } else if (!_cups_strcasecmp(line, "DefaultAuthType") && value) { /* @@ -3657,6 +3673,250 @@ read_configuration(cups_file_t *fp) /* I } +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", + "JobPrivateAccess", + "JobPrivateValues", + "LogFilePerm", + "PageLog", + "Printcap", + "PrintcapFormat", + "PrintcapGUI", + "RemoteRoot", + "RequestRoot", + "ServerBin", + "ServerCertificate", + "ServerKey", + "ServerRoot", + "StateDir", + "SubscriptionPrivateAccess", + "SubscriptionPrivateValues", + "SystemGroup", + "SystemGroupAuthKey", + "TempDir", + "User", + "WebInterface", + 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. */ -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
