]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
scheduler: Added remaining changes needed to run CUPS as a Snap
authorTill Kamppeter <till.kamppeter@gmail.com>
Tue, 2 Mar 2021 19:29:41 +0000 (20:29 +0100)
committerTill Kamppeter <till.kamppeter@gmail.com>
Tue, 2 Mar 2021 19:29:41 +0000 (20:29 +0100)
cupsd has a lot of functionality, especially for security, which does
not work under the confinement of a Snap. So these features need to
get removed or modified when CUPS is intended to get snapped, but
removing them does not necessarily weaken the security of the whole
thing, as the confinement of the Snap adds security replacing the one
removed from CUPS itself.

Most importantly a Snap cannot create several system groups and users.
Instead, it has a single unprivileged system user and a single
unprivileged system group, both named "snap_daemon". These are
replacing "lp" for running print jobs and filters, for administration
the user is root and as group first "lpadmin" and then "adm" is tried
and used if the host system has such a group. In all cases "root" is
also an admin group.

In addition, fiie ACLs do not work inside a Snap and the PATH and
LD_LIBRARY_PATH environment variables of the Snap are passed on to the
executables started by CUPS, so that they find their files and
libraries on the Snap-specific places.

Both the scheduler and the debugging tool cupsfilter are appropriately
modified.

This commit contains all changes to make the scheduler work under
these conditions, but to no compromise the security of an unsnapped
build of CUPS, conditional compiling is used. The changes are only
applied if the "--enable-snapped-cupsd" ./configure option is
used. Also the checking whether a client Snap doing administrative
tasks plugs "cups-control" (my previous commit) is then
active. "--enable-snapped-clients" is still available to do only the
client checking with an unsnapped scheduler.

All these changes got tested as packaging patches inn both the CUPS
Snap and the Debian/Ubuntu package of CUPS.

Note that this commit is not containing the changes on the
(machine-generated) ./configure script and so will not pass the CI
tests. An additional commit with an autoconf rebuild of ./configure is
needed.

CHANGES.md
config-scripts/cups-snap.m4
config.h.in
scheduler/auth.c
scheduler/cert.c
scheduler/conf.c
scheduler/cupsfilter.c
scheduler/env.c

index 3f9c74fc76c823f9b2c438a400a59fae1ae43769..05cb55c8c2044dff7812cba486293932bd34ae61 100644 (file)
@@ -5,6 +5,7 @@ CUPS v2.4rc1 (Pending)
 ----------------------
 
 - Added support for CUPS running in a snapcraft snap.
+- Added extra check for administrative inquiries from snapped clients.
 - The `testlang` unit test program now loops over all of the available locales
   by default (Issue #85)
 - The `cupsfilter` command now shows error messages when options are used
index a16446f1a5e17f63e836223b0089a4f0efb44e1a..206850011aaa52876b536933be65d97b9b05a726 100644 (file)
@@ -1,14 +1,14 @@
 dnl
-dnl Support for packaging CUPS in a Snap.
+dnl Support for packaging CUPS in a Snap and have it work with client Snaps.
 dnl
-dnl Copyright © 2020 by Till Kamppeter
-dnl Copyright © 2007-2019 by Apple Inc.
+dnl Copyright © 2021 by Till Kamppeter
+dnl Copyright © 2021 by OpenPrinting
 dnl
 dnl Licensed under Apache License v2.0.  See the file "LICENSE" for more
 dnl information.
 dnl
 
-# Snap packaging support
+# Snap packaging and Snap interaction support
 
 AC_ARG_ENABLE(snapped_cupsd, [  --enable-snapped-cupsd  enable support for packaging CUPS in a Snap])
 AC_ARG_ENABLE(snapped_clients, [  --enable-snapped-clients enable support for CUPS controlling admin access from snapped clients])
@@ -47,7 +47,8 @@ if test "x$PKGCONFIG" != x -a x$enable_snapped_clients == xyes; then
                        if test "x$SNAPCTL" != x && $SNAPCTL is-connected --help >/dev/null 2>&1; then
                                AC_MSG_RESULT(yes)
                                AC_DEFINE(HAVE_SNAPCTL_IS_CONNECTED)
-                               AC_DEFINE(BUILD_SNAP)
+                               AC_DEFINE(SUPPORT_SNAPPED_CUPSD)
+                               AC_DEFINE(SUPPORT_SNAPPED_CLIENTS)
                                ENABLE_SNAPPED_CUPSD="YES"
                                ENABLE_SNAPPED_CLIENTS="YES"
                        else
@@ -60,7 +61,7 @@ if test "x$PKGCONFIG" != x -a x$enable_snapped_clients == xyes; then
                                CFLAGS="$CFLAGS `$PKGCONFIG --cflags snapd-glib glib-2.0 gio-2.0`"
                                SNAPDGLIBLIBS="`$PKGCONFIG --libs snapd-glib glib-2.0 gio-2.0`"
                                AC_DEFINE(HAVE_SNAPDGLIB)
-                               AC_DEFINE(BUILD_SNAP)
+                               AC_DEFINE(SUPPORT_SNAPPED_CLIENTS)
                                ENABLE_SNAPPED_CLIENTS="YES"
                        else
                                AC_MSG_RESULT(no)
@@ -73,7 +74,11 @@ fi
 
 AC_MSG_CHECKING(for Snap support)
 if test "x$ENABLE_SNAPPED_CLIENTS" != "xNO"; then
-       AC_MSG_RESULT(yes)
+       if test "x$ENABLE_SNAPPED_CUPSD" != "xNO"; then
+               AC_MSG_RESULT(yes: cupsd + clients)
+       else
+               AC_MSG_RESULT(yes: clients only)
+       fi
 else
        AC_MSG_RESULT(no)
 fi
index 47b826c8bcd4e5911188b0e64e6d46f364445c00..7710edf3c295ce0c8997da4604e75dfba8d17448 100644 (file)
 #undef HAVE_SNAPCTL_IS_CONNECTED
 #undef SNAPCTL
 #undef CUPS_CONTROL_SLOT
-#undef BUILD_SNAP
+#undef SUPPORT_SNAPPED_CUPSD
+#undef SUPPORT_SNAPPED_CLIENTS
 
 /*
  * Location of macOS localization bundle, if any.
index 0107e15cc395e500d445cd1b1bd2fb01d1a4b963..6307e81d3f47d2717fe3f152ddc3551c9bde5d30 100644 (file)
@@ -51,13 +51,15 @@ typedef struct sockpeercred cupsd_ucred_t;
 #  endif
 #  define CUPSD_UCRED_UID(c) (c).uid
 #endif /* HAVE_SYS_UCRED_H */
-#ifdef BUILD_SNAP
-#  include <sys/apparmor.h>
+#ifdef SUPPORT_SNAPPED_CLIENTS
+#  ifdef HAVE_APPARMOR
+#    include <sys/apparmor.h>
+#  endif
 #  ifdef HAVE_SNAPDGLIB
 #    include <glib.h>
 #    include <snapd-glib/snapd-glib.h>
 #  endif
-#endif /* BUILD_SNAP */
+#endif /* SUPPORT_SNAPPED_CLIENTS */
 
 
 /*
@@ -1546,7 +1548,7 @@ cupsdCheckAdminTask(cupsd_client_t *con) /* I - Connection */
   * occurs in the process of finding this out.
   */
 
-#if defined(AF_LOCAL) && defined(BUILD_SNAP)
+#if defined(AF_LOCAL) && defined(SUPPORT_SNAPPED_CLIENTS)
 
  /*
   * Get the client's file descriptor and from this its AppArmor context
@@ -1565,7 +1567,7 @@ cupsdCheckAdminTask(cupsd_client_t *con) /* I - Connection */
     else
     {
       char *context = NULL; /* AppArmor profile name of client */
-#  ifdef HAVE_SNAPCTL_IS_CONNECTED
+#  if defined(SUPPORT_SNAPPED_CUPSD) && defined(HAVE_SNAPCTL_IS_CONNECTED)
       char buf[1024];
       char *argv[5];       /* snapctl command line */
       int fds[2],          /* Pipe file descriptors for stderr of snapctl */
@@ -1575,20 +1577,21 @@ cupsdCheckAdminTask(cupsd_client_t *con) /* I - Connection */
       int status = 65536;  /* Status of forked snapctl process */
       int wstatus;         /* Wait result of forked snapctl process */
 #  else
-#    ifdef HAVE_SNAPDGLIB
+#    if !defined(SUPPORT_SNAPPED_CUPSD) && defined(HAVE_SNAPDGLIB)
       char *snap_name = NULL;    /* Client Snap name */
       char *dot;                 /* Pointer to dot in AppArmor profile name */
       SnapdClient *snapd = NULL; /* Data structure of snapd access */
       SnapdSnap *snap = NULL;    /* Data structure of client Snap */
       GPtrArray *plugs = NULL;   /* Plug search result of client Snap */
       GError *error = NULL;      /* Glib error */
-#    endif /* HAVE_SNAPDGLIB */
-#  endif /* HAVE_SNAPCTL_IS_CONNECTED */
+#    endif /* !SUPPORT_SNAPPED_CUPSD && HAVE_SNAPDGLIB */
+#  endif /* SUPPORT_SNAPPED_CUPSD && HAVE_SNAPCTL_IS_CONNECTED */
+
 
-#  ifndef HAVE_SNAPCTL_IS_CONNECTED
+#  ifndef SUPPORT_SNAPPED_CUPSD
 
       /* If AppArmor is not enabled, then we can't identify the client */
-      /* With cupsd running in a Snaps, the "mount-observe" interface
+      /* With cupsd running in a Snap, the "mount-observe" interface
          needs to be plugged, therefore we do this only if not snapped. */
       if (!aa_is_enabled())
       {
@@ -1596,7 +1599,7 @@ cupsdCheckAdminTask(cupsd_client_t *con) /* I - Connection */
        goto snap_check_done;
       }
 
-#  endif /* !HAVE_SNAPCTL_IS_CONNECTED */
+#  endif /* !SUPPORT_SNAPPED_CUPSD */
 
       if (aa_getpeercon(peerfd, &context, NULL) < 0)
       {
@@ -1605,7 +1608,7 @@ cupsdCheckAdminTask(cupsd_client_t *con) /* I - Connection */
       } else
        cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCheckAdminTask: AppArmor profile of client process: %s", context);
 
-#  ifdef HAVE_SNAPCTL_IS_CONNECTED
+#  if defined(SUPPORT_SNAPPED_CUPSD) && defined(HAVE_SNAPCTL_IS_CONNECTED)
 
      /*
       * Run
@@ -1789,13 +1792,13 @@ cupsdCheckAdminTask(cupsd_client_t *con) /* I - Connection */
        free(context);
 
 #  else
-#    ifdef HAVE_SNAPDGLIB
+#    if !defined(SUPPORT_SNAPPED_CUPSD) && defined(HAVE_SNAPDGLIB)
 
      /*
       * If the client is a Snap, extract the client Snap's name from
-      * the AppArmor context and the query snapd to find out about the
-      * Snap's confinement type and whether it plugs
-      * cups-control. Grant access if
+      * the AppArmor context and then query snapd to find out about the
+      * Snap's confinement type and whether it plugs cups-control. Grant
+      * access if
       *
       *   - the client is not a Snap
       *   - the client is a classic Snap
@@ -1814,8 +1817,8 @@ cupsdCheckAdminTask(cupsd_client_t *con) /* I - Connection */
       *       Snap Store. This is the reason why the snapctl method
       *       (above) got created by the snapd developers.
       *
-      * This is the preferred method to run CUPS unsnapped, as is the
-      * only way to check Snap status on clients from an unsnapped
+      * This is the preferred method to run CUPS unsnapped, as this is
+      * the only way to check Snap status on clients from an unsnapped
       * cupsd.
       */
 
@@ -1903,16 +1906,20 @@ cupsdCheckAdminTask(cupsd_client_t *con) /* I - Connection */
       if (context)
        free(context);
 
-#    endif /* HAVE_SNAPDGLIB */
-#  endif /* HAVE_SNAPCTL_IS_CONNECTED */
+#    endif /* !SUPPORT_SNAPPED_CUPSD && HAVE_SNAPDGLIB */
+#  endif /* SUPPORT_SNAPPED_CUPSD && HAVE_SNAPCTL_IS_CONNECTED */
 
     }
   }
 
-#endif /* AF_LOCAL && BUILD_SNAP */
-
   cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCheckAdminTask: Access %s", ret == 1 ? "granted" : "denied");
 
+#else
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCheckAdminTask: Access granted (no extra checking)");
+
+#endif /* AF_LOCAL && SUPPORT_SNAPPED_CLIENTS */
+
   return ret;
 }
 
index 258e8fc83394e6eec96bdc192f3cc0c0f1893897..9716bbf3559d5a080ef96e9d488e3d497dc4c0d8 100644 (file)
@@ -83,7 +83,7 @@ cupsdAddCert(int        pid,          /* I - Process ID */
 
   if (pid == 0)
   {
-#ifdef HAVE_ACL_INIT
+#if defined(HAVE_ACL_INIT) && !defined(SUPPORT_SNAPPED_CUPSD)
     acl_t              acl;            /* ACL information */
     acl_entry_t                entry;          /* ACL entry */
     acl_permset_t      permset;        /* Permissions */
@@ -92,7 +92,7 @@ cupsdAddCert(int        pid,          /* I - Process ID */
 #  endif /* HAVE_MBR_UID_TO_UUID */
     static int         acls_not_supported = 0;
                                        /* Only warn once */
-#endif /* HAVE_ACL_INIT */
+#endif /* HAVE_ACL_INIT && !SUPPORT_SNAPPED_CUPSD */
 
 
    /*
@@ -100,11 +100,18 @@ cupsdAddCert(int        pid,              /* I - Process ID */
     */
 
     fchmod(fd, 0440);
+
+    /* ACLs do not work when cupsd is running in a Snap, and certificates
+       need root as group owner to be only accessible for CUPS and not the
+       unprivileged sub-processes */
+#ifdef SUPPORT_SNAPPED_CUPSD
+    fchown(fd, RunUser, 0);
+#else
     fchown(fd, RunUser, SystemGroupIDs[0]);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d", NumSystemGroups);
 
-#ifdef HAVE_ACL_INIT
+#  ifdef HAVE_ACL_INIT
     if (NumSystemGroups > 1)
     {
      /*
@@ -114,7 +121,7 @@ cupsdAddCert(int        pid,                /* I - Process ID */
 
       int      j;                      /* Looping var */
 
-#  ifdef HAVE_MBR_UID_TO_UUID
+#    ifdef HAVE_MBR_UID_TO_UUID
      /*
       * On macOS, ACLs use UUIDs instead of GIDs...
       */
@@ -143,7 +150,7 @@ cupsdAddCert(int        pid,                /* I - Process ID */
        acl_set_permset(entry, permset);
       }
 
-#  else
+#    else
      /*
       * POSIX ACLs need permissions for owner, group, other, and mask
       * in addition to the rest of the system groups...
@@ -215,7 +222,7 @@ cupsdAddCert(int        pid,                /* I - Process ID */
        cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
        acl_free(text);
       }
-#  endif /* HAVE_MBR_UID_TO_UUID */
+#    endif /* HAVE_MBR_UID_TO_UUID */
 
       if (acl_set_fd(fd, acl))
       {
@@ -230,7 +237,8 @@ cupsdAddCert(int        pid,                /* I - Process ID */
 
       acl_free(acl);
     }
-#endif /* HAVE_ACL_INIT */
+#  endif /* HAVE_ACL_INIT */
+#endif /* SUPPORT_SNAPPED_CUPSD */
 
     RootCertTime = time(NULL);
   }
index 74531a8c78392ce9ccd9faa21a86c71e504773e9..8944f69273565023221fccdc50e04a0c83a2db87 100644 (file)
@@ -1132,8 +1132,16 @@ cupsdReadConfiguration(void)
                             Group, 1, 1) < 0 ||
        cupsdCheckPermissions(StateDir, NULL, 0755, RunUser,
                             Group, 1, 1) < 0 ||
+       /* Inside a Snap cupsd is running as root without CAP_DAC_OVERRIDE
+         capability, so certs directory has to be root.root-owned so that
+         cupsd can access but not its unprivileged sub-processes. */
+#ifdef SUPPORT_SNAPPED_CUPSD
+       cupsdCheckPermissions(StateDir, "certs", 0711, RunUser,
+                            0, 1, 1) < 0 ||
+#else
        cupsdCheckPermissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
                             SystemGroupIDs[0], 1, 1) < 0 ||
+#endif /* SUPPORT_SNAPPED_CUPSD */
        cupsdCheckPermissions(ServerRoot, NULL, 0755, RunUser,
                             Group, 1, 0) < 0 ||
        cupsdCheckPermissions(ServerRoot, "ppd", 0755, RunUser,
index 54f6ba5b85bfd4fd69d6d1ba2bd2b570eeef00ff..9772242c9ba896571d2c883189524b3f960bff45 100644 (file)
@@ -970,7 +970,11 @@ exec_filters(mime_type_t   *srctype,       /* I - Source type */
 {
   int          i;                      /* Looping var */
   const char   *argv[8],               /* Command-line arguments */
+#ifdef SUPPORT_SNAPPED_CUPSD
+               *envp[21],              /* Environment variables */
+#else
                *envp[17],              /* Environment variables */
+#endif /* SUPPORT_SNAPPED_CUPSD */
                *temp;                  /* Temporary string */
   char         *optstr,                /* Filter options */
                content_type[1024],     /* CONTENT_TYPE */
@@ -978,9 +982,17 @@ exec_filters(mime_type_t   *srctype,       /* I - Source type */
                cups_fontpath[1024],    /* CUPS_FONTPATH */
                cups_serverbin[1024],   /* CUPS_SERVERBIN */
                cups_serverroot[1024],  /* CUPS_SERVERROOT */
+#ifdef SUPPORT_SNAPPED_CUPSD
+               fontconfig_file[1024],  /* FONTCONFIG_FILE */
+               fontconfig_path[1024],  /* FONTCONFIG_PATH */
+               fontconfig_sysroot[1024], /* FONTCONFIG_SYSROOT */
+#endif /* SUPPORT_SNAPPED_CUPSD */
                final_content_type[1024] = "",
                                        /* FINAL_CONTENT_TYPE */
                lang[1024],             /* LANG */
+#ifdef SUPPORT_SNAPPED_CUPSD
+               ld_library_path[2048],  /* LD_LIBRARY_PATH */
+#endif /* SUPPORT_SNAPPED_CUPSD */
                path[1024],             /* PATH */
                ppd[1024],              /* PPD */
                printer_info[255],      /* PRINTER_INFO env variable */
@@ -1039,6 +1051,9 @@ exec_filters(mime_type_t   *srctype,      /* I - Source type */
   * Setup the filter environment and command-line...
   */
 
+  /* If we are running confined in a Snap, also pass on fontconfig-related
+     environment variables and LD_LIBRARY_PATH */
+
   optstr = escape_options(num_options, options);
 
   snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
@@ -1049,8 +1064,20 @@ exec_filters(mime_type_t   *srctype,     /* I - Source type */
            ServerBin);
   snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s",
            ServerRoot);
+#ifdef SUPPORT_SNAPPED_CUPSD
+  snprintf(fontconfig_file, sizeof(fontconfig_file), "FONTCONFIG_FILE=%s",
+           getenv("FONTCONFIG_FILE"));
+  snprintf(fontconfig_path, sizeof(fontconfig_path), "FONTCONFIG_PATH=%s",
+           getenv("FONTCONFIG_PATH"));
+  snprintf(fontconfig_sysroot, sizeof(fontconfig_sysroot),
+          "FONTCONFIG_SYSROOT=%s", getenv("FONTCONFIG_SYSROOT"));
+#endif /* SUPPORT_SNAPPED_CUPSD */
   language = cupsLangDefault();
   snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language);
+#ifdef SUPPORT_SNAPPED_CUPSD
+  snprintf(ld_library_path, sizeof(ld_library_path), "LD_LIBRARY_PATH=%s",
+          getenv("LD_LIBRARY_PATH"));
+#endif /* SUPPORT_SNAPPED_CUPSD */
   snprintf(path, sizeof(path), "PATH=%s", Path);
   if (ppdfile)
     snprintf(ppd, sizeof(ppd), "PPD=%s", ppdfile);
@@ -1122,6 +1149,26 @@ exec_filters(mime_type_t   *srctype,     /* I - Source type */
   envp[5]  = cups_serverroot;
   envp[6]  = lang;
   envp[7]  = path;
+#ifdef SUPPORT_SNAPPED_CUPSD
+  envp[8]  = ld_library_path;
+  envp[9]  = ppd;
+  envp[10] = printer_info;
+  envp[11] = printer_location;
+  envp[12] = printer_name;
+  envp[13] = rip_max_cache;
+  envp[14] = userenv;
+  envp[15] = "CHARSET=utf-8";
+  envp[16] = fontconfig_file;
+  envp[17] = fontconfig_path;
+  envp[18] = fontconfig_sysroot;
+  if (final_content_type[0])
+  {
+    envp[19] = final_content_type;
+    envp[20] = NULL;
+  }
+  else
+    envp[19] = NULL;
+#else
   envp[8]  = ppd;
   envp[9]  = printer_info;
   envp[10] = printer_location;
@@ -1136,6 +1183,7 @@ exec_filters(mime_type_t   *srctype,      /* I - Source type */
   }
   else
     envp[15] = NULL;
+#endif /* SUPPORT_SNAPPED_CUPSD */
 
   for (i = 0; argv[i]; i ++)
     fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
@@ -1467,7 +1515,14 @@ read_cups_files_conf(
     cupsFileClose(fp);
   }
 
+  /* Set the PATH environment variable for external executables, pass
+     through the PATH from the environment in which cupsd was called
+     if we are running confined in a Snap */
+#ifdef SUPPORT_SNAPPED_CUPSD
+  snprintf(line, sizeof(line), "%s/filter:%s:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin:/usr/bin", ServerBin, getenv("PATH"));
+#else
   snprintf(line, sizeof(line), "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin:/usr/bin", ServerBin);
+#endif /* SUPPORT_SNAPPED_CUPSD */
   set_string(&Path, line);
 
   return (0);
index 71ab98d6b8b642f704e061a77d2fa4dd46bf3d39..71af88416b9556ffe81430e634135d67c51327fb 100644 (file)
@@ -114,11 +114,14 @@ cupsdSetEnv(const char *name,             /* I - Name of variable */
     return;
 
  /*
-  * Do not allow dynamic linker variables when running as root...
+  * Do not allow dynamic linker variables when running as root and
+  * not being confined in a Snap...
   */
 
+#ifndef SUPPORT_SNAPPED_CUPSD
   if (!RunUser && (!strncmp(name, "DYLD_", 5) || !strncmp(name, "LD_", 3)))
     return;
+#endif /* !SUPPORT_SNAPPED_CUPSD */
 
  /*
   * See if this variable has already been defined...
@@ -208,9 +211,19 @@ cupsdUpdateEnv(void)
   set_if_undefined("LD_LIBRARY_PATH", NULL);
   set_if_undefined("LD_PRELOAD", NULL);
   set_if_undefined("NLSPATH", NULL);
+  /* Only if cupsd is confined in a Snap we pass the PATH environment
+     variable on for external executables we call */
   if (find_env("PATH") < 0)
-    cupsdSetEnvf("PATH", "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR
-                        ":/bin:/usr/bin", ServerBin);
+  {
+#ifdef SUPPORT_SNAPPED_CUPSD
+    char *value;
+    if ((value = getenv("PATH")) != NULL)
+      cupsdSetEnvf("PATH", "%s/filter:%s", ServerBin, value);
+    else
+#endif /* SUPPORT_SNAPPED_CUPSD */
+      cupsdSetEnvf("PATH", "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR
+                  ":/bin:/usr/bin", ServerBin);
+  }
   set_if_undefined("SERVER_ADMIN", ServerAdmin);
   set_if_undefined("SHLIB_PATH", NULL);
   set_if_undefined("SOFTWARE", CUPS_MINIMAL);