From 8e46966dd352dff5306de5fbd38086c5ba3bdb3d Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Wed, 6 Oct 2021 10:42:34 -0400 Subject: [PATCH] Clean up and simplify snap support. --- config-scripts/cups-container.m4 | 2 +- configure | 348 ++---------------- scheduler/auth.c | 612 +++++++++---------------------- scheduler/cert.c | 16 +- scheduler/conf.c | 13 +- scheduler/cups-exec.c | 10 +- scheduler/cupsfilter.c | 131 +++---- scheduler/env.c | 21 +- scheduler/process.c | 12 +- 9 files changed, 294 insertions(+), 871 deletions(-) diff --git a/config-scripts/cups-container.m4 b/config-scripts/cups-container.m4 index 2190103fdd..278f0d9a24 100644 --- a/config-scripts/cups-container.m4 +++ b/config-scripts/cups-container.m4 @@ -10,7 +10,7 @@ dnl dnl Specify a container mode CONTAINER="none" -AC_ARG_WITH([container], AS_HELP_STRING([--with-container=...], [configure to use in container ('none', 'snap')]), [ +AC_ARG_WITH([container], AS_HELP_STRING([--with-container=...], [configure to use in container (none, snap)]), [ CONTAINER="$withval" ]) diff --git a/configure b/configure index 43bcf2daa2..f2161c2536 100755 --- a/configure +++ b/configure @@ -694,7 +694,6 @@ ONDEMANDLIBS ONDEMANDFLAGS SNAPDGLIBLIBS APPARMORLIBS -SNAPCTL IPPFIND_MAN IPPFIND_BIN DNSSD_BACKEND @@ -904,11 +903,7 @@ enable_largefile with_dnssd with_dnssd_libs with_dnssd_includes -enable_snapped_cupsd -enable_snapped_clients -with_our_snap_name -with_snapctl -with_cups_control_slot +with_container with_ondemand with_systemd with_smfmanifestdir @@ -1599,10 +1594,6 @@ Optional Features: --enable-gssapi enable (deprecated) GSSAPI/Kerberos support --disable-pam disable PAM support --disable-largefile omit support for large files - --enable-snapped-cupsd enable support for packaging CUPS in a Snap - --enable-snapped-clients - enable support for CUPS controlling admin access - from snapped clients --enable-page-logging enable page_log by default --enable-sync-on-close enable SyncOnClose (off by default) --disable-browsing disable Browsing by default @@ -1641,14 +1632,7 @@ Optional Packages: mdnsresponder, no, yes) --with-dnssd-libs set directory for DNS Service Discovery library --with-dnssd-includes set directory for DNS Service Discovery header files - --with-our-snap-name Set name of the Snap we are snapped in, only needed - with --enable-snapped-cupsd, default=cups - --with-snapctl Set path for snapctl, only needed with - --enable-snapped-cupsd, default=/usr/bin/snapctl - --with-cups-control-slot - Name for cups-control slot as defined in - snapcraft.yaml, only needed with - --enable-snapped-cupsd, default=cups-control + --with-container=... configure to use in container (none, snap) --with-ondemand=... Specify the on-demand launch interface (launchd, systemd, upstart) --with-systemd set directory for systemd service files @@ -10763,80 +10747,45 @@ fi -# Check whether --enable-snapped_cupsd was given. -if test ${enable_snapped_cupsd+y} -then : - enableval=$enable_snapped_cupsd; -fi +CONTAINER="none" -# Check whether --enable-snapped_clients was given. -if test ${enable_snapped_clients+y} -then : - enableval=$enable_snapped_clients; -fi - -# Check whether --with-our-snap-name was given. -if test ${with_our_snap_name+y} +# Check whether --with-container was given. +if test ${with_container+y} then : - withval=$with_our_snap_name; - OUR_SNAP_NAME="$withval" - -else $as_nop - - OUR_SNAP_NAME="cups" + withval=$with_container; + CONTAINER="$withval" fi -printf "%s\n" "#define OUR_SNAP_NAME \"$OUR_SNAP_NAME\"" >>confdefs.h - - -# Check whether --with-snapctl was given. -if test ${with_snapctl+y} -then : - withval=$with_snapctl; - SNAPCTL="$withval" - -else $as_nop - - SNAPCTL="/usr/bin/snapctl" +case "$CONTAINER" in #( + none) : -fi - - -printf "%s\n" "#define SNAPCTL \"$SNAPCTL\"" >>confdefs.h - - -# Check whether --with-cups_control_slot was given. -if test ${with_cups_control_slot+y} -then : - withval=$with_cups_control_slot; - CUPS_CONTROL_SLOT="$withval" - -else $as_nop + # No container in use + ;; #( + snap) : - CUPS_CONTROL_SLOT="cups-control" + # Building as a snap -fi +printf "%s\n" "#define CUPS_SNAP 1" >>confdefs.h + ;; #( + *) : -printf "%s\n" "#define CUPS_CONTROL_SLOT \"$CUPS_CONTROL_SLOT\"" >>confdefs.h + as_fn_error $? "Unsupported container '$CONTAINER' specified." "$LINENO" 5 + ;; #( + *) : + ;; +esac APPARMORLIBS="" SNAPDGLIBLIBS="" -ENABLE_SNAPPED_CUPSD="NO" -ENABLE_SNAPPED_CLIENTS="NO" -if test x$enable_snapped_cupsd = xyes -then : - enable_snapped_clients="yes" -fi - -if test "x$PKGCONFIG" != x -a x$enable_snapped_clients = xyes +if "x$PKGCONFIG" != x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libapparmor" >&5 @@ -10847,15 +10796,14 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } - CFLAGS="$CFLAGS $($PKGCONFIG --cflags libapparmor)" - APPARMORLIBS="$($PKGCONFIG --libs libapparmor)" + CFLAGS="$CFLAGS $($PKGCONFIG --cflags libapparmor)" + APPARMORLIBS="$($PKGCONFIG --libs libapparmor)" -printf "%s\n" "#define HAVE_APPARMOR 1" >>confdefs.h +printf "%s\n" "#define HAVE_LIBAPPARMOR 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libsnapd-glib" >&5 printf %s "checking for libsnapd-glib... " >&6; } - if $PKGCONFIG --exists snapd-glib glib-2.0 gio-2.0 then : @@ -10864,266 +10812,34 @@ printf "%s\n" "yes" >&6; } CFLAGS="$CFLAGS $($PKGCONFIG --cflags snapd-glib glib-2.0 gio-2.0)" SNAPDGLIBLIBS="$($PKGCONFIG --libs snapd-glib glib-2.0 gio-2.0)" -printf "%s\n" "#define HAVE_SNAPDGLIB 1" >>confdefs.h - - -else $as_nop - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - -fi - - if test x$enable_snapped_cupsd = xyes -then : +printf "%s\n" "#define HAVE_LIBSNAPDGLIB 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for snapd_client_run_snapctl2_sync in -lsnapd-glib" >&5 -printf %s "checking for snapd_client_run_snapctl2_sync in -lsnapd-glib... " >&6; } -if test ${ac_cv_lib_snapd_glib_snapd_client_run_snapctl2_sync+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsnapd-glib $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char snapd_client_run_snapctl2_sync (); -int -main (void) -{ -return snapd_client_run_snapctl2_sync (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_snapd_glib_snapd_client_run_snapctl2_sync=yes -else $as_nop - ac_cv_lib_snapd_glib_snapd_client_run_snapctl2_sync=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_snapd_glib_snapd_client_run_snapctl2_sync" >&5 -printf "%s\n" "$ac_cv_lib_snapd_glib_snapd_client_run_snapctl2_sync" >&6; } -if test "x$ac_cv_lib_snapd_glib_snapd_client_run_snapctl2_sync" = xyes + SAVELIBS="$LIBS" + LIBS="$SNAPDGLIBLIBS $LIBS" + ac_fn_c_check_func "$LINENO" "snapd_client_run_snapctl2_sync" "ac_cv_func_snapd_client_run_snapctl2_sync" +if test "x$ac_cv_func_snapd_client_run_snapctl2_sync" = xyes then : printf "%s\n" "#define HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC 1" >>confdefs.h -printf "%s\n" "#define SUPPORT_SNAPPED_CUPSD 1" >>confdefs.h - - -printf "%s\n" "#define SUPPORT_SNAPPED_CLIENTS 1" >>confdefs.h - - ENABLE_SNAPPED_CUPSD="YES" - ENABLE_SNAPPED_CLIENTS="YES" - -else $as_nop - - if test "x$SNAPDGLIBLIBS" != "x" -then : - - SNAPDGLIBLIBS="" - fi - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}snapctl", so it can be a program name with args. -set dummy ${ac_tool_prefix}snapctl; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_SNAPCTL+y} -then : - printf %s "(cached) " >&6 -else $as_nop - case $SNAPCTL in - [\\/]* | ?:[\\/]*) - ac_cv_path_SNAPCTL="$SNAPCTL" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_SNAPCTL="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - ;; -esac -fi -SNAPCTL=$ac_cv_path_SNAPCTL -if test -n "$SNAPCTL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SNAPCTL" >&5 -printf "%s\n" "$SNAPCTL" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_path_SNAPCTL"; then - ac_pt_SNAPCTL=$SNAPCTL - # Extract the first word of "snapctl", so it can be a program name with args. -set dummy snapctl; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_ac_pt_SNAPCTL+y} -then : - printf %s "(cached) " >&6 -else $as_nop - case $ac_pt_SNAPCTL in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_SNAPCTL="$ac_pt_SNAPCTL" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_SNAPCTL="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -ac_pt_SNAPCTL=$ac_cv_path_ac_pt_SNAPCTL -if test -n "$ac_pt_SNAPCTL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_SNAPCTL" >&5 -printf "%s\n" "$ac_pt_SNAPCTL" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_pt_SNAPCTL" = x; then - SNAPCTL="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - SNAPCTL=$ac_pt_SNAPCTL - fi -else - SNAPCTL="$ac_cv_path_SNAPCTL" -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for snapctl is-connected support" >&5 -printf %s "checking for snapctl is-connected support... " >&6; } - if test "x$SNAPCTL" != x && $SNAPCTL is-connected --help >/dev/null 2>&1 -then : - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - -printf "%s\n" "#define HAVE_SNAPCTL_IS_CONNECTED 1" >>confdefs.h - - -printf "%s\n" "#define SUPPORT_SNAPPED_CUPSD 1" >>confdefs.h - - -printf "%s\n" "#define SUPPORT_SNAPPED_CLIENTS 1" >>confdefs.h - - ENABLE_SNAPPED_CUPSD="YES" - ENABLE_SNAPPED_CLIENTS="YES" - -else $as_nop - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - -fi - -fi - - -else $as_nop - - if test "x$SNAPDGLIBLIBS" != "x" -then : - - -printf "%s\n" "#define SUPPORT_SNAPPED_CLIENTS 1" >>confdefs.h - - ENABLE_SNAPPED_CLIENTS="YES" - -fi - -fi + LIBS="$SAVELIBS" else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Snap support" >&5 -printf %s "checking for Snap support... " >&6; } -if test "x$ENABLE_SNAPPED_CLIENTS" != "xNO" -then : - - if test "x$ENABLE_SNAPPED_CUPSD" != "xNO" -then : - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: cupsd + clients" >&5 -printf "%s\n" "yes: cupsd + clients" >&6; } - -else $as_nop - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: clients only" >&5 -printf "%s\n" "yes: clients only" >&6; } - -fi - -else $as_nop - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - fi - - - ONDEMANDFLAGS="" ONDEMANDLIBS="" diff --git a/scheduler/auth.c b/scheduler/auth.c index d124bfd1d5..0de70e6b1b 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -65,7 +65,7 @@ typedef struct sockpeercred cupsd_ucred_t; * Local functions... */ -static int check_admin_task(cupsd_client_t *con); +static int check_admin_access(cupsd_client_t *con); #ifdef HAVE_AUTHORIZATION_H static int check_authref(cupsd_client_t *con, const char *right); #endif /* HAVE_AUTHORIZATION_H */ @@ -1841,7 +1841,7 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ if (!_cups_strcasecmp(name, "@SYSTEM")) { for (i = 0; i < NumSystemGroups; i ++) - if (cupsdCheckGroup(username, pw, SystemGroups[i]) && check_admin_task(con)) + if (cupsdCheckGroup(username, pw, SystemGroups[i]) && check_admin_access(con)) return (HTTP_OK); } } @@ -1884,7 +1884,7 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: Checking group \"%s\" membership...", name); for (i = 0; i < NumSystemGroups; i ++) - if (cupsdCheckGroup(username, pw, SystemGroups[i]) && check_admin_task(con)) + if (cupsdCheckGroup(username, pw, SystemGroups[i]) && check_admin_access(con)) return (HTTP_OK); } } @@ -1940,481 +1940,209 @@ cupsdNewLocation(const char *location) /* I - Location path */ /* - * 'check_admin_task()' - Do additional checks on administrative tasks + * 'check_admin_access()' - Verify that the client has administrative access. */ -static int /* O - 1 if admin task authorized */ -check_admin_task(cupsd_client_t *con) /* I - Connection */ +static int // O - 1 if authorized, 0 otherwise +check_admin_access(cupsd_client_t *con) // I - Client connection { - int ret = 1; /* Return value */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Administrative task"); - +#if defined(HAVE_LIBAPPARMOR) && defined(HAVE_LIBSNAPDGLIB) /* * If the client accesses locally via domain socket, find out whether it - * is a Snap. Grant access if it is not a Snap, if it is a classic Snap - * or if it is a confined Snap which plugs "cups-control", deny access - * if it is a confined Snap not plugging "cups-control" or if an error - * occurs in the process of finding this out. - */ - -#if defined(AF_LOCAL) && defined(SUPPORT_SNAPPED_CLIENTS) - - /* - * Get the client's file descriptor and from this its AppArmor context + * is a Snap. Grant access if it is not a Snap, if it is a classic Snap + * or if it is a confined Snap which plugs "cups-control". Otherwise deny + * access. */ - if (httpAddrFamily(con->http->hostaddr) == AF_LOCAL) - { - int peerfd; /* Peer's file descriptor */ - - peerfd = httpGetFd(con->http); - - if (peerfd < 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Unable to get peer file descriptor of client connecting via domain socket"); - } - else - { - char *context = NULL; /* AppArmor profile name of client */ -# undef CHECK_METHOD_FOUND -# ifdef SUPPORT_SNAPPED_CUPSD - int status = 65535; /* Status of client Snap context check */ -# if defined(HAVE_SNAPDGLIB) && defined(HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC) -# define CHECK_METHOD_FOUND 1 - char *args[] = { "is-connected", "--apparmor-label", NULL, CUPS_CONTROL_SLOT, NULL }; /* snapctl arguments */ - SnapdClient *client = NULL; /* Data structure of snapd access */ - const char *cookie; /* snapd access cookie */ - GError *error = NULL; /* Glib error */ -# else -# ifdef HAVE_SNAPCTL_IS_CONNECTED -# define CHECK_METHOD_FOUND 1 - char *args[] = { SNAPCTL, "is-connected", "--apparmor-label", NULL, CUPS_CONTROL_SLOT, NULL }; /* snapctl command line */ - int fds[2], /* Pipe file descriptors for stderr of - snapctl */ - nullfd; /* /dev/null file descriptor for stdout of - snapctl */ - pid_t pid; /* PID of snapctl */ - cups_file_t *snapctl_stderr; /* CUPS FP for stderr of snapctl */ - char buf[1024]; /* Buffer for snapctl's stderr output */ - int wstatus; /* Wait result of forked snapctl process */ -# endif /* HAVE_SNAPCTL_IS_CONNECTED */ -# endif /* HAVE_SNAPDGLIB && HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC */ -# else -# if !defined(SUPPORT_SNAPPED_CUPSD) && defined(HAVE_SNAPDGLIB) -# define CHECK_METHOD_FOUND 1 - char *snap_name = NULL; /* Client Snap name */ - char *dot; /* Pointer to dot in AppArmor profile name */ - SnapdClient *snapd = NULL; /* Data structure of snapd access */ - GError *error = NULL; /* Glib error */ - SnapdSnap *snap = NULL; /* Data structure of client Snap */ - GPtrArray *plugs = NULL; /* Plug search result of client Snap */ -# endif /* !SUPPORT_SNAPPED_CUPSD && HAVE_SNAPDGLIB */ -# endif /* SUPPORT_SNAPPED_CUPSD */ - - -# ifndef SUPPORT_SNAPPED_CUPSD - - /* If AppArmor is not enabled, then we can't identify the client */ - /* 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()) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: No AppArmor in use"); - goto snap_check_done; - } - -# endif /* !SUPPORT_SNAPPED_CUPSD */ - - if (aa_getpeercon(peerfd, &context, NULL) < 0) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: AppArmor profile could not be retrieved for client process - Error: %s", strerror(errno)); - goto snap_check_done; - } else - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: AppArmor profile of client process: %s", context); - -# ifdef OUR_SNAP_NAME - /* Is the client one of the utilities of our Snap? */ - if (!strncmp(context, "snap." OUR_SNAP_NAME ".", strlen(OUR_SNAP_NAME) + 6)) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client Snap is the same Snap we are running in, access granted"); - goto snap_check_done; - } -# endif /* OUR_SNAP_NAME */ - -# ifdef SUPPORT_SNAPPED_CUPSD - - /* - * Run - * - * snapctl is-connected --apparmor-label AA_CONTEXT CUPS_CONTROL_SLOT - * - * or an equivalent library function call using the - * snapd_client_run_snapctl2_sync() function of libsnapd-glib. - * - * Here AA_CONTEXT is the AppArmor profile name of the client, or - * "unconfined" for an unconfined client and CUPS_CONTROL_SLOT - * the name of the slot of the CUPS Snap to which clients plug - * with their cups-control plug in order to do administrative - * CUPS tasks. - * - * The exit status of the command/function call tells which type - * of client we have to do with: - * - * 0: The client is a confined Snap and plugs cups-control - * -> Grant access - * 1: The client is a confined Snap and does not plug cups-control - * -> Deny access - * 10: The client is a classic Snap - * -> Grant access - * 11: The client is not a Snap - * -> Grant access - * - * NOTE: This method only works if cupsd is running in a Snap - * providing a slot for the client's "cups-control" - * plug. Do not build CUPS with this method when intending - * to use it unsnapped, for example in a Debian or RPM - * package, or directly installed into your system. The - * errors of snapctl missing or snapctl/the function - * running without a Snap context will deny all - * administrative accesses! - * - * When running inside a Snap this method is preferred, as it does not - * require full access to the snapd under which cupsd is running. - */ - -# if defined(HAVE_SNAPDGLIB) && defined(HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC) - - /* - * Use the snapd_client_run_snapctl2_sync() function of libsnapd-glib - */ - - /* Insert client Snap context in snapctl arguments */ - args[2] = context; - - /* Connect to snapd */ - client = snapd_client_new(); - if (!client) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Could not connect to snapd, permission denied"); - ret = 0; - goto snap_check_done; - } - - /* snapctl commands are sent over a this socket that is made - available within the snap sandbox */ - snapd_client_set_socket_path(client, "/run/snapd-snap.socket"); + int fd = httpGetFd(con->http); + // Client socket file descriptor + char *context = NULL; // AppArmor profile name of client + SnapdClient *client = NULL; // Data structure of snapd access + GError *error = NULL; // Glib error + int ret = 1; // Return value - /* Take cookie from the environment if available */ - cookie = g_getenv("SNAP_COOKIE"); - if (!cookie) - { - cookie = ""; - cupsdLogMessage(CUPSD_LOG_WARN, "check_admin_task: No SNAP_COOKIE set in the Snap environment, client Snap context check may not work"); - } - - /* Do the client Snap context check */ - if (!snapd_client_run_snapctl2_sync(client, cookie, args, NULL, NULL, &status, NULL, &error)) { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client Snap context check error - %s", error->message); - ret = 0; - goto snap_check_done; - } - -# else -# ifdef HAVE_SNAPCTL_IS_CONNECTED - - /* - * Call the snapctl executable using execv() in a fork - */ - /* Insert client Snap context in snapctl command line */ - args[3] = context; - - /* Create a pipe to catch stderr output from snapctl */ - if (pipe(fds)) - { - fds[0] = -1; - fds[1] = -1; - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Unable to establish stderr pipe for snapctl call - %s", strerror(errno)); - ret = 0; - goto snap_check_done; - } - - /* Set the "close on exec" flag on each end of the pipe... */ - if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC)) - { - close(fds[0]); - close(fds[1]); - fds[0] = -1; - fds[1] = -1; - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Unable to set \"close on exec\" flag on read end of the stderr pipe for snapctl call - %s", strerror(errno)); - ret = 0; - goto snap_check_done; - } - if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC)) - { - close(fds[0]); - close(fds[1]); - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Unable to set \"close on exec\" flag on write end of the stderr pipe for snapctl call - %s", strerror(errno)); - ret = 0; - goto snap_check_done; - } - - if ((pid = fork()) == 0) - { - /* Couple pipe with stderr of Ghostscript process */ - if (fds[1] >= 0) { - if (fds[1] != 2) { - if (dup2(fds[1], 2) < 0) { - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Unable to couple pipe with stderr of snapctl process - %s", strerror(errno)); - exit(100); - } - close(fds[1]); - } - close(fds[0]); - } else { - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Invalid pipe file descriptor to couple with stderr of snapctl process - %s", strerror(errno)); - exit(100); - } - - /* Send snapctl's stdout to the Nirwana, as snapctl is supposed to - not output anything here */ - if ((nullfd = open("/dev/null", O_RDWR)) > 2) - { - dup2(nullfd, 1); - close(nullfd); - } - else - close(nullfd); - fcntl(1, F_SETFL, O_NDELAY); - - /* Execute snapctl command line ... */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Running command: " SNAPCTL " is-connected --apparmor-label %s " CUPS_CONTROL_SLOT, context); - execv(SNAPCTL, args); - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Unable to launch snapctl: %s", strerror(errno)); - exit(100); - } - else if (pid < 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Unable to fork for snapctl call - %s", strerror(errno)); - ret = 0; - goto snap_check_done; - } - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Started snapctl (PID %d)", pid); - - close(fds[1]); - - /* Read out stderr from snapctl */ - buf[0] = '\0'; - snapctl_stderr = cupsFileOpenFd(fds[0], "r"); - if (snapctl_stderr) - { - while (cupsFileGets(snapctl_stderr, buf, sizeof(buf)) && buf[0]) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: Error message from snapctl: %s", buf); - ret = 0; - } - cupsFileClose(snapctl_stderr); - } - close(fds[0]); +# ifdef AF_LOCAL + // Only check domain sockets... + if (httpAddrFamily(con->http->hostaddr) != AF_LOCAL) + return (1); +# endif // AF_LOCAL - /* Wait for snapctl to finish */ - retry_wait: - if (waitpid (pid, &wstatus, 0) == -1) - { - if (errno == EINTR) - goto retry_wait; - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: snapctl (PID %d) stopped with an error - %s", pid, strerror(errno)); - ret = 0; - goto snap_check_done; - } - if (ret == 0) - goto snap_check_done; - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: snapctl (PID %d) exited with no errors.", pid); +# if !CUPS_SNAP + // If AppArmor is not enabled, then we can't identify the client... + if (!aa_is_enabled()) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "AppArmor not in use."); + return (1); + } +# endif /* !CUPS_SNAP */ - /* How did snapctl terminate */ - if (WIFEXITED(wstatus)) - { - /* Via regular exit */ - status = WEXITSTATUS(wstatus); - if (status == 100) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: snapctl not executed"); - ret = 0; - goto snap_check_done; - } - } - else if (WIFSIGNALED(wstatus)) - { - /* Via signal */ - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: snapctl caught the signal %d", WTERMSIG(wstatus)); - ret = 0; - goto snap_check_done; - } + // Get the client's AppArmor context using the socket... + if (aa_getpeercon(fd, &context, NULL) < 0) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "AppArmor profile could not be retrieved: %s", strerror(errno)); + return (1); + } + else + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "AppArmor profile is '%s'.", context); + } -# endif /* HAVE_SNAPCTL_IS_CONNECTED */ -# endif /* HAVE_SNAPDGLIB && HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC */ + // Allow access from "cups" snap... + if (!strncmp(context, "snap.cups.", 10)) + goto done; - switch (status) - { - case 0 : - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client Snap connecting via \"cups-control\" interface, access granted"); - break; - case 1 : - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client Snap does not connect via \"cups-control\" interface, permission denied"); - ret = 0; - break; - case 10 : - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client Snap under classic confinement, access granted"); - break; - case 11 : - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client is not a Snap, access granted"); - break; - default : - cupsdLogMessage(CUPSD_LOG_ERROR, "check_admin_task: snapctl exited with unknown status: %d", status); - ret = 0; - break; - } +# if CUPS_SNAP && defined(HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC) + /* + * CUPS is snapped, so check whether the client is also snapped. If so, + * determine whether the client snap has a "cups-control" plug which allows + * the application to perform CUPS administrative tasks. + */ - snap_check_done: - if (context) - free(context); -# if defined(HAVE_SNAPDGLIB) && defined(HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC) - g_clear_object(&client); -# endif /* HAVE_SNAPDGLIB && HAVE_SNAPD_CLIENT_RUN_SNAPCTL2_SYNC */ + const char *cookie; // snapd access cookie + int status = 65535; // Status of client Snap context check + const char *args[] = // snapctl arguments + { + "is-connected", + "--apparmor-label", + NULL, + "cups-control", + NULL + }; + + // Connect to snapd + if ((client = snapd_client_new()) == NULL) + { + cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to connect to snapd."); + ret = 0; + goto done; + } -# else -# if !defined(SUPPORT_SNAPPED_CUPSD) && defined(HAVE_SNAPDGLIB) + // snapctl commands are sent over a domain socket + snapd_client_set_socket_path(client, "/run/snapd-snap.socket"); - /* - * If the client is a Snap, extract the client Snap's name from - * 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 - * - the client is a confined Snap plugging "cups-control" - * - * We deny access if - * - * - the client is a confined Snap not plugging "cups-control" - * - an error occurs during the steps of this method - * - * NOTE: This method is only for use of cupsd when it is not - * packaged in a Snap. In a Snap one would need to plug the - * snapd-control interface, which gives full control on - * snapd, a high security risk. Therefore one will not get - * automatic connection of this interface granted in the - * 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 this is - * the only way to check Snap status on clients from an unsnapped - * cupsd. - */ + // Take cookie from the environment if available + if ((cookie = g_getenv("SNAP_COOKIE")) == NULL) + { + cookie = ""; + cupsdLogClient(CUPSD_LOG_WARN, "No SNAP_COOKIE set in the Snap environment."); + } - /* If the AppArmor context does not begin with "snap.", then this - is not a snap */ - if (strncmp(context, "snap.", 5) != 0) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: AppArmor context not from a Snap"); - goto snap_check_done; - } + // Do the client Snap context check... + args[2] = context; - dot = strchr(context + 5, '.'); - if (dot == NULL) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Malformed snapd AppArmor profile name: %s", context); - goto snap_check_done; - } - snap_name = strndup(context + 5, (size_t)(dot - context - 5)); - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client is the Snap %s", snap_name); + if (!snapd_client_run_snapctl2_sync(client, cookie, args, NULL, NULL, &status, NULL, &error)) + { + cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to check snap context: %s", error->message); + ret = 0; + goto done; + } - /* Connect to snapd */ - snapd = snapd_client_new(); - if (!snapd) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Could not connect to snapd, permission denied"); + switch (status) + { + case 0 : // The client is a confined Snap and plugs cups-control + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Snap with cups-control plug - allowed."); + break; + case 1 : // The client is a confined Snap and does not plug cups-control + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Snap without cups-control plug - denied."); ret = 0; - goto snap_check_done; - } - - /* Check whether the client Snap is under classic confinement */ - snap = snapd_client_get_snap_sync(snapd, snap_name, NULL, &error); - if (!snap) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Could not obtain client Snap data: \"%s\", permission denied", error->message); + break; + case 10 : // The client is a classic Snap + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Classic snap - allowed."); + break; + case 11 : // The client is not a Snap + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Not a snap - allowed."); + break; + default : // Unexpected status... + cupsdLogClient(con, CUPSD_LOG_ERROR, "Snap check returned unexpected status %d - denied.", status); ret = 0; - goto snap_check_done; - } + break; + } - /* Snaps using classic confinement are granted access */ - if (snapd_snap_get_confinement(snap) == SNAPD_CONFINEMENT_CLASSIC) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client Snap under classic confinement, access granted"); - goto snap_check_done; - } +# elif !CUPS_SNAP + /* + * If CUPS is not snapped, check whether the client is snapped and if it has + * the "cups-control" plug. + */ - /* Get list of interfaces to which the client Snap is plugging */ - if (!snapd_client_get_connections2_sync(snapd, SNAPD_GET_CONNECTIONS_FLAGS_NONE, snap_name, "cups-control", NULL, NULL, &plugs, NULL, NULL, &error)) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Could not obtain the client Snap's interface connections: \"%s\", permission denied", error->message); - ret = 0; - goto snap_check_done; - } + // Is the client a snapped application? + if (strncmp(context, "snap.", 5)) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Not a snap - allowed."); + goto done; + } - if (plugs->len <= 0) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client Snap does not connect via \"cups-control\" interface, permission denied"); - ret = 0; - goto snap_check_done; - } + // Extract the snap name from the context (snap.name.instance) + char *snap_name = strdup(context + 5);// Snap name follows "snap." + char *ptr = strchr(snap_name, '.'); // instance follows the name... + if (!ptr) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Malformed snapd AppArmor profile name '%s' - denied.", context); + free(snap_name); + ret = 0; + goto done; + } - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Client Snap connecting via \"cups-control\" interface, access granted"); + *ptr = '\0'; + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Client snap is '%s'.", snap_name); - snap_check_done: - if (context) - free(context); - if (snap_name) - free(snap_name); - g_clear_object(&snapd); - g_clear_object(&snap); - if (plugs) - g_ptr_array_unref(plugs); + // Connect to snapd + if ((client = snapd_client_new()) == NULL) + { + cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to connect to snapd."); + free(snap_name); + ret = 0; + goto done; + } -# endif /* !SUPPORT_SNAPPED_CUPSD && HAVE_SNAPDGLIB */ -# endif /* SUPPORT_SNAPPED_CUPSD */ + // Check whether the client Snap is under classic confinement + GPtrArray *plugs = NULL; // List of plugs for snap -# ifndef CHECK_METHOD_FOUND + if ((snap = snapd_client_get_snap_sync(client, snap_name, NULL, &error)) == NULL) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Unable to get client Snap data: %s", error->message); + ret = 0; + } + // Snaps using classic confinement are granted access + else if (snapd_snap_get_confinement(snap) == SNAPD_CONFINEMENT_CLASSIC) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Classic snap - allowed."); + } + // Check whether the client Snap has the cups-control plug + else if (!snapd_client_get_connections2_sync(snapd, SNAPD_GET_CONNECTIONS_FLAGS_NONE, snap_name, "cups-control", NULL, NULL, &plugs, NULL, NULL, &error)) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Unable to get client Snap plugs: %s", error->message); + ret = 0; + } + else if (plugs->len <= 0) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Snap without cups-control plug - denied."); + ret = 0; + } + else + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Snap with cups-control plug - allowed."); + } - /* - * Issue warning if requirements for building Snap-related access control - * not fulfilled - */ + if (plugs) + g_ptr_array_unref(plugs); - cupsdLogMessage(CUPSD_LOG_WARN, "check_admin_task: Compiling problem: none of the three access control methods (libsnapd-glib snapd access, \"snapctl is-connected\", libsnapd-glib-based snapctl call) available, no Snap-related access control built!"); + free(snap_name); + g_clear_object(&snap); - snap_check_done: - if (context) - free(context); +# endif // CUPS_SNAP -# endif /* !CHECK_METHOD_FOUND */ + done: - } - } + free(context); + g_clear_object(&client); - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Access %s", ret == 1 ? "granted" : "denied"); + return (ret); #else - - (void)con; - cupsdLogMessage(CUPSD_LOG_DEBUG, "check_admin_task: Access granted (no extra checking)"); - -#endif /* AF_LOCAL && SUPPORT_SNAPPED_CLIENTS */ - - return ret; + // No AppArmor/snapd to deal with... + return (1); +#endif // HAVE_LIBAPPARMOR && HAVE_LIBSNAPDGLIB } diff --git a/scheduler/cert.c b/scheduler/cert.c index 9716bbf355..a0c3941bd4 100644 --- a/scheduler/cert.c +++ b/scheduler/cert.c @@ -1,10 +1,12 @@ /* * Authentication certificate routines for the CUPS scheduler. * - * Copyright 2007-2016 by Apple Inc. - * Copyright 1997-2006 by Easy Software Products. + * Copyright © 2021 by OpenPrinting. + * Copyright © 2007-2016 by Apple Inc. + * Copyright © 1997-2006 by Easy Software Products. * - * Licensed under Apache License v2.0. See the file "LICENSE" for more information. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -83,7 +85,7 @@ cupsdAddCert(int pid, /* I - Process ID */ if (pid == 0) { -#if defined(HAVE_ACL_INIT) && !defined(SUPPORT_SNAPPED_CUPSD) +#if defined(HAVE_ACL_INIT) && !CUPS_SNAP acl_t acl; /* ACL information */ acl_entry_t entry; /* ACL entry */ acl_permset_t permset; /* Permissions */ @@ -92,7 +94,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 && !SUPPORT_SNAPPED_CUPSD */ +#endif /* HAVE_ACL_INIT && !CUPS_SNAP */ /* @@ -104,7 +106,7 @@ cupsdAddCert(int pid, /* I - Process ID */ /* 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 +#if CUPS_SNAP fchown(fd, RunUser, 0); #else fchown(fd, RunUser, SystemGroupIDs[0]); @@ -238,7 +240,7 @@ cupsdAddCert(int pid, /* I - Process ID */ acl_free(acl); } # endif /* HAVE_ACL_INIT */ -#endif /* SUPPORT_SNAPPED_CUPSD */ +#endif /* CUPS_SNAP */ RootCertTime = time(NULL); } diff --git a/scheduler/conf.c b/scheduler/conf.c index 5d167e0fe8..e44736b77d 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -1121,16 +1121,11 @@ 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 || +#if CUPS_SNAP + 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(StateDir, "certs", RunUser ? 0711 : 0511, User, SystemGroupIDs[0], 1, 1) < 0 || +#endif /* CUPS_SNAP */ cupsdCheckPermissions(ServerRoot, NULL, 0755, RunUser, Group, 1, 0) < 0 || cupsdCheckPermissions(ServerRoot, "ppd", 0755, RunUser, diff --git a/scheduler/cups-exec.c b/scheduler/cups-exec.c index dff5055158..7b851d33c6 100644 --- a/scheduler/cups-exec.c +++ b/scheduler/cups-exec.c @@ -1,9 +1,11 @@ /* * Sandbox helper for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright © 2021 by OpenPrinting. + * Copyright © 2007-2014 by Apple Inc. * - * Licensed under Apache License v2.0. See the file "LICENSE" for more information. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. * * Usage: * @@ -129,11 +131,11 @@ main(int argc, /* I - Number of command-line args */ if (setgid(gid)) exit(errno + 100); -# ifdef SUPPORT_SNAPPED_CUPSD +# if CUPS_SNAP if (setgroups(0, NULL)) # else if (setgroups(1, &gid)) -# endif /* SUPPORT_SNAPPED_CUPSD */ +# endif /* CUPS_SNAP */ exit(errno + 100); if (uid && setuid(uid)) diff --git a/scheduler/cupsfilter.c b/scheduler/cupsfilter.c index d9192b4242..c6dbb8debb 100644 --- a/scheduler/cupsfilter.c +++ b/scheduler/cupsfilter.c @@ -965,11 +965,7 @@ 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 */ @@ -977,17 +973,9 @@ 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 */ @@ -995,6 +983,13 @@ exec_filters(mime_type_t *srctype, /* I - Source type */ printer_name[255], /* PRINTER env variable */ rip_max_cache[1024], /* RIP_MAX_CACHE */ userenv[1024], /* USER */ +#if CUPS_SNAP + fontconfig_file[1024], /* FONTCONFIG_FILE */ + fontconfig_path[1024], /* FONTCONFIG_PATH */ + fontconfig_sysroot[1024], + /* FONTCONFIG_SYSROOT */ + ld_library_path[2048], /* LD_LIBRARY_PATH */ +#endif /* CUPS_SNAP */ program[1024]; /* Program to run */ mime_filter_t *filter, /* Current filter */ *next; /* Next filter */ @@ -1046,9 +1041,6 @@ 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", @@ -1058,20 +1050,8 @@ 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); @@ -1090,8 +1070,9 @@ exec_filters(mime_type_t *srctype, /* I - Source type */ "Versions/A/Frameworks/PrintCore.framework/Versions/A/" "Resources/Generic.ppd", sizeof(ppd)); #else - snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir); + snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir); #endif /* __APPLE__ */ + snprintf(userenv, sizeof(userenv), "USER=%s", user); if (printer && @@ -1134,52 +1115,54 @@ exec_filters(mime_type_t *srctype, /* I - Source type */ if (!argv[4]) argv[4] = "1"; - envp[0] = ""; - envp[1] = content_type; - envp[2] = cups_datadir; - envp[3] = cups_fontpath; - envp[4] = cups_serverbin; - 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; + for (i = 0; argv[i]; i ++) + fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]); + + i = 0; +#ifdef __APPLE__ + envp[i ++] = ""; +#endif /* __APPLE__ */ + envp[i ++] = content_type; + envp[i ++] = cups_datadir; + envp[i ++] = cups_fontpath; + envp[i ++] = cups_serverbin; + envp[i ++] = cups_serverroot; + envp[i ++] = lang; + envp[i ++] = path; + envp[i ++] = ppd; + envp[i ++] = printer_info; + envp[i ++] = printer_location; + envp[i ++] = printer_name; + envp[i ++] = rip_max_cache; + envp[i ++] = userenv; + envp[i ++] = "CHARSET=utf-8"; if (final_content_type[0]) + envp[i ++] = final_content_type; + +#if CUPS_SNAP + if ((temp = getenv("FONTCONFIG_FILE")) != NULL) { - envp[19] = final_content_type; - envp[20] = NULL; + snprintf(fontconfig_file, sizeof(fontconfig_file), "FONTCONFIG_FILE=%s", temp); + envp[i ++] = fontconfig_file; } - else - envp[19] = NULL; -#else - envp[8] = ppd; - envp[9] = printer_info; - envp[10] = printer_location; - envp[11] = printer_name; - envp[12] = rip_max_cache; - envp[13] = userenv; - envp[14] = "CHARSET=utf-8"; - if (final_content_type[0]) + if ((temp = getenv("FONTCONFIG_PATH")) != NULL) { - envp[15] = final_content_type; - envp[16] = NULL; + snprintf(fontconfig_path, sizeof(fontconfig_path), "FONTCONFIG_PATH=%s", temp); + envp[i ++] = fontconfig_path; } - else - envp[15] = NULL; -#endif /* SUPPORT_SNAPPED_CUPSD */ + if ((temp = getenv("FONTCONFIG_SYSROOT")) != NULL) + { + snprintf(fontconfig_sysroot, sizeof(fontconfig_sysroot), "FONTCONFIG_SYSROOT=%s", temp); + envp[i ++] = fontconfig_sysroot; + } + if ((temp = getenv("LD_LIBRARY_PATH")) != NULL) + { + snprintf(ld_library_path, sizeof(ld_library_path), "LD_LIBRARY_PATH=%s", temp); + envp[i ++] = ld_library_path; + } +#endif /* CUPS_SNAP */ - for (i = 0; argv[i]; i ++) - fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]); + envp[i] = NULL; for (i = 0; envp[i]; i ++) fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]); @@ -1497,14 +1480,12 @@ 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 +#if CUPS_SNAP + if ((temp = getenv("PATH")) != NULL) + snprintf(line, sizeof(line), "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":%s", ServerBin, temp); + else +#endif /* CUPS_SNAP */ snprintf(line, sizeof(line), "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin:/usr/bin", ServerBin); -#endif /* SUPPORT_SNAPPED_CUPSD */ set_string(&Path, line); return (0); diff --git a/scheduler/env.c b/scheduler/env.c index 09d79676c9..87b9cdd35b 100644 --- a/scheduler/env.c +++ b/scheduler/env.c @@ -116,14 +116,13 @@ cupsdSetEnv(const char *name, /* I - Name of variable */ return; /* - * Do not allow dynamic linker variables when running as root and - * not being confined in a Snap... + * Do not allow dynamic linker variables when running as root outside a Snap... */ -#ifndef SUPPORT_SNAPPED_CUPSD +#if !CUPS_SNAP if (!RunUser && (!strncmp(name, "DYLD_", 5) || !strncmp(name, "LD_", 3))) return; -#endif /* !SUPPORT_SNAPPED_CUPSD */ +#endif /* !CUPS_SNAP */ /* * See if this variable has already been defined... @@ -212,18 +211,16 @@ 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) { -#ifdef SUPPORT_SNAPPED_CUPSD - char *value; - if ((value = getenv("PATH")) != NULL) +#if CUPS_SNAP + const char *path; // PATH environment variable + + if ((path = 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); +#endif /* CUPS_SNAP */ + cupsdSetEnvf("PATH", "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin:/usr/bin", ServerBin); } set_if_undefined("SERVER_ADMIN", ServerAdmin); set_if_undefined("SHLIB_PATH", NULL); diff --git a/scheduler/process.c b/scheduler/process.c index 3b09efe24c..d995be231e 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -1,10 +1,12 @@ /* * Process management routines for the CUPS scheduler. * - * Copyright 2007-2017 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2021 by OpenPrinting. + * Copyright © 2007-2017 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * - * Licensed under Apache License v2.0. See the file "LICENSE" for more information. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -744,11 +746,11 @@ cupsdStartProcess( if (!RunUser && setgid(Group)) exit(errno + 100); -# ifdef SUPPORT_SNAPPED_CUPSD +# if CUPS_SNAP if (!RunUser && setgroups(0, NULL)) # else if (!RunUser && setgroups(1, &Group)) -# endif /* SUPPORT_SNAPPED_CUPSD */ +# endif /* CUPS_SNAP */ exit(errno + 100); /* -- 2.47.2