=== modified file 'debian/changelog' --- debian/changelog 2012-11-27 03:39:25 +0000 +++ debian/changelog 2012-11-27 03:46:44 +0000 @@ -1,3 +1,14 @@ +cups-pk-helper (0.1.2-1ubuntu1) oneiric-security; urgency=low + + * SECURITY UPDATE: CUPS function calls were wrapped insecurely, which + could be used to upload sensitive data to a CUPS resource, or overwrite + specific files with the content of a CUPS resource. The user would have + to explicitly approve the action. (LP: #1083416) + - CVE-2012-4510 + - debian/patches/cups-pk-helper-CVE-2012-4510.patch: Copied from Fedora 16 + + -- Jeremy Bicha Mon, 26 Nov 2012 22:39:36 -0500 + cups-pk-helper (0.1.2-1) unstable; urgency=low * [019a316] New upstream version 0.1.2 (Closes: #622366) === modified file 'debian/control' --- debian/control 2012-11-27 03:39:25 +0000 +++ debian/control 2012-11-27 03:58:27 +0000 @@ -1,7 +1,8 @@ Source: cups-pk-helper Section: gnome Priority: extra -Maintainer: Guido Günther +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Guido Günther Build-Depends: debhelper (>= 7.0.50~), autotools-dev, intltool, === added directory 'debian/patches' === added file 'debian/patches/cups-pk-helper-CVE-2012-4510.patch' --- debian/patches/cups-pk-helper-CVE-2012-4510.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/cups-pk-helper-CVE-2012-4510.patch 2012-11-27 03:55:51 +0000 @@ -0,0 +1,425 @@ +Description: CVE-2012-4510 security fix +Bug: https://bugs.launchpad.net/ubuntu/bugs/1083416 +Origin: http://koji.fedoraproject.org/koji/buildinfo?buildID=361830 +--- cups-pk-helper-0.1.3/src/cups.c 2012-10-18 16:17:16.000000000 +0200 ++++ cups-pk-helper-0.1.3/src/cups.c 2012-10-18 16:17:27.000000000 +0200 +@@ -28,6 +28,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -469,6 +471,84 @@ _CPH_CUPS_IS_VALID (filename, "filename" + * Helpers + ******************************************************/ + ++static gboolean ++_cph_cups_set_effective_id (unsigned int sender_uid, ++ int *saved_ngroups, ++ gid_t **saved_groups) ++{ ++ struct passwd *password_entry; ++ int ngroups; ++ gid_t *groups; ++ ++ /* avoid g_assert() because we don't want to crash here */ ++ if (saved_ngroups == NULL || saved_groups == NULL) { ++ g_critical ("Internal error: cannot save supplementary groups."); ++ return FALSE; ++ } ++ ++ *saved_ngroups = -1; ++ *saved_groups = NULL; ++ ++ ngroups = getgroups (0, NULL); ++ if (ngroups < 0) ++ return FALSE; ++ ++ groups = g_new (gid_t, ngroups); ++ if (groups == NULL && ngroups > 0) ++ return FALSE; ++ ++ if (getgroups (ngroups, groups) < 0) { ++ g_free (groups); ++ ++ return FALSE; ++ } ++ ++ password_entry = getpwuid ((uid_t) sender_uid); ++ ++ if (password_entry == NULL || ++ setegid (password_entry->pw_gid) != 0) { ++ g_free (groups); ++ ++ return FALSE; ++ } ++ ++ if (initgroups (password_entry->pw_name, ++ password_entry->pw_gid) != 0) { ++ if (getgid () != getegid ()) ++ setegid (getgid ()); ++ ++ g_free (groups); ++ ++ return FALSE; ++ } ++ ++ ++ if (seteuid (sender_uid) != 0) { ++ if (getgid () != getegid ()) ++ setegid (getgid ()); ++ ++ setgroups (ngroups, groups); ++ g_free (groups); ++ ++ return FALSE; ++ } ++ ++ *saved_ngroups = ngroups; ++ *saved_groups = groups; ++ ++ return TRUE; ++} ++ ++static void ++_cph_cups_reset_effective_id (int saved_ngroups, ++ gid_t *saved_groups) ++{ ++ seteuid (getuid ()); ++ setegid (getgid ()); ++ if (saved_ngroups >= 0) ++ setgroups (saved_ngroups, saved_groups); ++} ++ + static void + _cph_cups_add_printer_uri (ipp_t *request, + const char *name) +@@ -1013,14 +1093,17 @@ cph_cups_is_printer_local (CphCups *c + } + + gboolean +-cph_cups_file_get (CphCups *cups, +- const char *resource, +- const char *filename) ++cph_cups_file_get (CphCups *cups, ++ const char *resource, ++ const char *filename, ++ unsigned int sender_uid) + { ++ int saved_ngroups = -1; ++ gid_t *saved_groups = NULL; + http_status_t status; ++ int fd; + struct stat file_stat; +- uid_t uid; +- gid_t gid; ++ char *error; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + +@@ -1029,44 +1112,87 @@ cph_cups_file_get (CphCups *cups, + if (!_cph_cups_is_filename_valid (cups, filename)) + return FALSE; + +- stat (filename, &file_stat); +- uid = file_stat.st_uid; +- gid = file_stat.st_gid; ++ if (!_cph_cups_set_effective_id (sender_uid, ++ &saved_ngroups, &saved_groups)) { ++ error = g_strdup_printf ("Cannot check if \"%s\" is " ++ "writable: %s", ++ filename, strerror (errno)); ++ _cph_cups_set_internal_status (cups, error); ++ g_free (error); ++ ++ return FALSE; ++ } ++ ++ fd = open (filename, O_WRONLY | O_NOFOLLOW | O_TRUNC); ++ ++ _cph_cups_reset_effective_id (saved_ngroups, saved_groups); ++ g_free (saved_groups); ++ ++ if (fd < 0) { ++ error = g_strdup_printf ("Cannot open \"%s\": %s", ++ filename, strerror (errno)); ++ _cph_cups_set_internal_status (cups, error); ++ g_free (error); ++ ++ return FALSE; ++ } ++ ++ ++ if (fstat (fd, &file_stat) != 0) { ++ error = g_strdup_printf ("Cannot write to \"%s\": %s", ++ filename, strerror (errno)); ++ _cph_cups_set_internal_status (cups, error); ++ g_free (error); ++ ++ close (fd); ++ ++ return FALSE; ++ } ++ ++ if (!S_ISREG (file_stat.st_mode)) { ++ /* hrm, this looks suspicious... we won't help */ ++ error = g_strdup_printf ("File \"%s\" is not a regular file.", ++ filename); ++ _cph_cups_set_internal_status (cups, error); ++ g_free (error); ++ ++ close (fd); ++ ++ return FALSE; ++ } + + /* reset the internal status: we'll use the http status */ + _cph_cups_set_internal_status (cups, NULL); + +- status = cupsGetFile (cups->priv->connection, resource, filename); ++ status = cupsGetFd (cups->priv->connection, resource, fd); + + /* FIXME: There's a bug where the cups connection can fail with EPIPE. +- * We're work-arounding it here until it's fixed in cups. */ ++ * We're working around it here until it's fixed in cups. */ + if (status != HTTP_OK) { +- if (cph_cups_reconnect (cups)) { +- int fd; +- +- /* if cupsGetFile fail, then filename is unlinked */ +- fd = open (filename, O_CREAT, S_IRUSR | S_IWUSR); +- close (fd); +- chown (filename, uid, gid); +- +- _cph_cups_set_internal_status (cups, NULL); +- +- status = cupsGetFile (cups->priv->connection, +- resource, filename); +- } ++ if (cph_cups_reconnect (cups)) ++ status = cupsGetFd (cups->priv->connection, ++ resource, fd); + } + ++ close (fd); ++ + _cph_cups_set_internal_status_from_http (cups, status); + + return (status == HTTP_OK); + } + + gboolean +-cph_cups_file_put (CphCups *cups, +- const char *resource, +- const char *filename) ++cph_cups_file_put (CphCups *cups, ++ const char *resource, ++ const char *filename, ++ unsigned int sender_uid) + { ++ int saved_ngroups = -1; ++ gid_t *saved_groups = NULL; + http_status_t status; ++ int fd; ++ struct stat file_stat; ++ char *error; + + g_return_val_if_fail (CPH_IS_CUPS (cups), FALSE); + +@@ -1075,10 +1201,60 @@ cph_cups_file_put (CphCups *cups, + if (!_cph_cups_is_filename_valid (cups, filename)) + return FALSE; + ++ if (!_cph_cups_set_effective_id (sender_uid, ++ &saved_ngroups, &saved_groups)) { ++ error = g_strdup_printf ("Cannot check if \"%s\" is " ++ "readable: %s", ++ filename, strerror (errno)); ++ _cph_cups_set_internal_status (cups, error); ++ g_free (error); ++ ++ return FALSE; ++ } ++ ++ fd = open (filename, O_RDONLY); ++ ++ _cph_cups_reset_effective_id (saved_ngroups, saved_groups); ++ g_free (saved_groups); ++ ++ if (fd < 0) { ++ error = g_strdup_printf ("Cannot open \"%s\": %s", ++ filename, strerror (errno)); ++ _cph_cups_set_internal_status (cups, error); ++ g_free (error); ++ ++ return FALSE; ++ } ++ ++ if (fstat (fd, &file_stat) != 0) { ++ error = g_strdup_printf ("Cannot read \"%s\": %s", ++ filename, strerror (errno)); ++ _cph_cups_set_internal_status (cups, error); ++ g_free (error); ++ ++ close (fd); ++ ++ return FALSE; ++ } ++ ++ if (!S_ISREG (file_stat.st_mode)) { ++ /* hrm, this looks suspicious... we won't help */ ++ error = g_strdup_printf ("File \"%s\" is not a regular file.", ++ filename); ++ _cph_cups_set_internal_status (cups, error); ++ g_free (error); ++ ++ close (fd); ++ ++ return FALSE; ++ } ++ + /* reset the internal status: we'll use the http status */ + _cph_cups_set_internal_status (cups, NULL); + +- status = cupsPutFile (cups->priv->connection, resource, filename); ++ status = cupsPutFd (cups->priv->connection, resource, fd); ++ ++ close (fd); + + _cph_cups_set_internal_status_from_http (cups, status); + +--- cups-pk-helper-0.1.3/src/cups.h 2011-07-05 14:07:05.000000000 +0200 ++++ cups-pk-helper-0.1.3/src/cups.h 2012-10-18 16:17:27.000000000 +0200 +@@ -70,13 +70,15 @@ char *cph_cups_printer_get_uri (CphCups + gboolean cph_cups_is_printer_local (CphCups *cups, + const char *printer_name); + +-gboolean cph_cups_file_get (CphCups *cups, +- const char *resource, +- const char *filename); ++gboolean cph_cups_file_get (CphCups *cups, ++ const char *resource, ++ const char *filename, ++ unsigned int sender_uid); + +-gboolean cph_cups_file_put (CphCups *cups, +- const char *resource, +- const char *filename); ++gboolean cph_cups_file_put (CphCups *cups, ++ const char *resource, ++ const char *filename, ++ unsigned int sender_uid); + + GHashTable *cph_cups_server_get_settings (CphCups *cups); + +--- cups-pk-helper-0.1.3/src/cups-pk-helper-mechanism.c 2012-10-18 16:17:16.000000000 +0200 ++++ cups-pk-helper-0.1.3/src/cups-pk-helper-mechanism.c 2012-10-19 10:44:02.000000000 +0200 +@@ -426,6 +426,41 @@ _cph_mechanism_get_action_for_name (CphM + return "printer-remote-edit"; + } + ++static gboolean ++_cph_mechanism_get_sender_uid (CphMechanism *mechanism, ++ DBusGMethodInvocation *context, ++ unsigned int *sender_uid) ++{ ++ unsigned long uid; ++ DBusError error; ++ gchar *sender; ++ ++ *sender_uid = 0; ++ ++ sender = dbus_g_method_get_sender (context); ++ dbus_error_init (&error); ++ uid = dbus_bus_get_unix_user ( ++ dbus_g_connection_get_connection (mechanism->priv->system_bus_connection), ++ sender, &error); ++ ++ g_free (sender); ++ ++ if (uid == (unsigned long ) -1) { ++ if (dbus_error_is_set (&error)) { ++ g_warning ("Could not get unix user: %s", error.message); ++ dbus_error_free (&error); ++ } else { ++ g_warning ("Could not get unix user"); ++ } ++ ++ return FALSE; ++ } else { ++ *sender_uid = uid; ++ } ++ ++ return TRUE; ++} ++ + static char * + _cph_mechanism_get_callers_user_name (CphMechanism *mechanism, + DBusGMethodInvocation *context) +@@ -496,14 +531,29 @@ cph_mechanism_file_get (CphMechanism + const char *filename, + DBusGMethodInvocation *context) + { +- gboolean ret; ++ unsigned int sender_uid; ++ gboolean ret; + + reset_killtimer (mechanism); + ++ if (!_cph_mechanism_get_sender_uid (mechanism, context, &sender_uid)) { ++ GError *error; ++ ++ error = g_error_new (CPH_MECHANISM_ERROR, ++ CPH_MECHANISM_ERROR_GENERAL, ++ "Cannot determine sender UID"); ++ dbus_g_method_return_error (context, error); ++ g_error_free (error); ++ ++ return; ++ } ++ + if (!_check_polkit_for_action (mechanism, context, "server-settings")) + return; + +- ret = cph_cups_file_get (mechanism->priv->cups, resource, filename); ++ ret = cph_cups_file_get (mechanism->priv->cups, ++ resource, filename, sender_uid); ++ + _cph_mechanism_return_error (mechanism, context, !ret); + } + +@@ -513,14 +563,29 @@ cph_mechanism_file_put (CphMechanism + const char *filename, + DBusGMethodInvocation *context) + { +- gboolean ret; ++ unsigned int sender_uid; ++ gboolean ret; + + reset_killtimer (mechanism); + ++ if (!_cph_mechanism_get_sender_uid (mechanism, context, &sender_uid)) { ++ GError *error; ++ ++ error = g_error_new (CPH_MECHANISM_ERROR, ++ CPH_MECHANISM_ERROR_GENERAL, ++ "Cannot determine sender UID"); ++ dbus_g_method_return_error (context, error); ++ g_error_free (error); ++ ++ return; ++ } ++ + if (!_check_polkit_for_action (mechanism, context, "server-settings")) + return; + +- ret = cph_cups_file_put (mechanism->priv->cups, resource, filename); ++ ret = cph_cups_file_put (mechanism->priv->cups, ++ resource, filename, sender_uid); ++ + _cph_mechanism_return_error (mechanism, context, !ret); + } + === added file 'debian/patches/series' --- debian/patches/series 1970-01-01 00:00:00 +0000 +++ debian/patches/series 2012-11-27 03:45:49 +0000 @@ -0,0 +1,1 @@ +cups-pk-helper-CVE-2012-4510.patch