|
|
393a40 |
diff -up cups-filters-1.0.35/NEWS.CVE-2014-4337 cups-filters-1.0.35/NEWS
|
|
|
393a40 |
diff -up cups-filters-1.0.35/utils/cups-browsed.c.CVE-2014-4337 cups-filters-1.0.35/utils/cups-browsed.c
|
|
|
393a40 |
--- cups-filters-1.0.35/utils/cups-browsed.c.CVE-2014-4337 2014-10-08 13:33:12.192067445 +0100
|
|
|
393a40 |
+++ cups-filters-1.0.35/utils/cups-browsed.c 2014-10-08 13:54:45.742569979 +0100
|
|
|
393a40 |
@@ -298,6 +298,75 @@ create_local_queue (const char *name,
|
|
|
393a40 |
return p;
|
|
|
393a40 |
}
|
|
|
393a40 |
|
|
|
393a40 |
+/*
|
|
|
393a40 |
+ * Remove all illegal characters and replace each group of such characters
|
|
|
393a40 |
+ * by a single dash, return a free()-able string.
|
|
|
393a40 |
+ *
|
|
|
393a40 |
+ * mode = 0: Only allow letters, numbers, and dashes, for turning make/model
|
|
|
393a40 |
+ * info into a valid print queue name or into a string which can
|
|
|
393a40 |
+ * be supplied as option value in a filter command line without
|
|
|
393a40 |
+ * need of quoting
|
|
|
393a40 |
+ * mode = 1: Allow also '/', '.', ',', '_', for cleaning up MIME type
|
|
|
393a40 |
+ * strings (here available Page Description Languages, PDLs) to
|
|
|
393a40 |
+ * supply them on a filter command line without quoting
|
|
|
393a40 |
+ *
|
|
|
393a40 |
+ * Especially this prevents from arbitrary code execution by interface scripts
|
|
|
393a40 |
+ * generated for print queues to native IPP printers when a malicious IPP
|
|
|
393a40 |
+ * print service with forged PDL and/or make/model info gets broadcasted into
|
|
|
393a40 |
+ * the local network.
|
|
|
393a40 |
+ */
|
|
|
393a40 |
+
|
|
|
393a40 |
+char * /* O - Cleaned string */
|
|
|
393a40 |
+remove_bad_chars(const char *str_orig, /* I - Original string */
|
|
|
393a40 |
+ int mode) /* I - 0: Make/Model, queue name */
|
|
|
393a40 |
+ /* 1: MIME types/PDLs */
|
|
|
393a40 |
+{
|
|
|
393a40 |
+ int i, j;
|
|
|
393a40 |
+ int havedash = 0;
|
|
|
393a40 |
+ char *str;
|
|
|
393a40 |
+
|
|
|
393a40 |
+ if (str_orig == NULL)
|
|
|
393a40 |
+ return NULL;
|
|
|
393a40 |
+
|
|
|
393a40 |
+ str = strdup(str_orig);
|
|
|
393a40 |
+
|
|
|
393a40 |
+ /* for later str[strlen(str)-1] access */
|
|
|
393a40 |
+ if (strlen(str) < 1)
|
|
|
393a40 |
+ return str;
|
|
|
393a40 |
+
|
|
|
393a40 |
+ for (i = 0, j = 0; i < strlen(str); i++, j++) {
|
|
|
393a40 |
+ if (((str[i] >= 'A') && (str[i] <= 'Z')) ||
|
|
|
393a40 |
+ ((str[i] >= 'a') && (str[i] <= 'z')) ||
|
|
|
393a40 |
+ ((str[i] >= '0') && (str[i] <= '9')) ||
|
|
|
393a40 |
+ (mode == 1 && (str[i] == '/' || str[i] == '_' ||
|
|
|
393a40 |
+ str[i] == '.' || str[i] == ','))) {
|
|
|
393a40 |
+ /* Letter or number, keep it */
|
|
|
393a40 |
+ havedash = 0;
|
|
|
393a40 |
+ } else {
|
|
|
393a40 |
+ /* Replace all other characters by a single '-' */
|
|
|
393a40 |
+ if (havedash == 1)
|
|
|
393a40 |
+ j --;
|
|
|
393a40 |
+ else {
|
|
|
393a40 |
+ havedash = 1;
|
|
|
393a40 |
+ str[j] = '-';
|
|
|
393a40 |
+ }
|
|
|
393a40 |
+ }
|
|
|
393a40 |
+ }
|
|
|
393a40 |
+ /* Add terminating zero */
|
|
|
393a40 |
+ str[j] = '\0';
|
|
|
393a40 |
+ /* Cut off trailing dashes */
|
|
|
393a40 |
+ while (str[strlen(str)-1] == '-')
|
|
|
393a40 |
+ str[strlen(str)-1] = '\0';
|
|
|
393a40 |
+
|
|
|
393a40 |
+ /* Cut off leading dashes */
|
|
|
393a40 |
+ i = 0;
|
|
|
393a40 |
+ while (str[i] == '-')
|
|
|
393a40 |
+ ++i;
|
|
|
393a40 |
+
|
|
|
393a40 |
+ /* keep a free()-able string. +1 for trailing \0 */
|
|
|
393a40 |
+ return memmove(str, str + i, strlen(str) - i + 1);
|
|
|
393a40 |
+}
|
|
|
393a40 |
+
|
|
|
393a40 |
gboolean handle_cups_queues(gpointer unused) {
|
|
|
393a40 |
remote_printer_t *p;
|
|
|
393a40 |
http_t *http;
|
|
|
393a40 |
@@ -392,7 +461,7 @@ gboolean handle_cups_queues(gpointer unu
|
|
|
393a40 |
}
|
|
|
393a40 |
if (default_printer_name)
|
|
|
393a40 |
break;
|
|
|
393a40 |
- }
|
|
|
393a40 |
+ }
|
|
|
393a40 |
}
|
|
|
393a40 |
if (default_printer_name &&
|
|
|
393a40 |
!strcasecmp(default_printer_name, p->name)) {
|
|
|
393a40 |
@@ -572,19 +641,30 @@ void generate_local_queue(const char *ho
|
|
|
393a40 |
const char *name,
|
|
|
393a40 |
const char *type,
|
|
|
393a40 |
const char *domain) {
|
|
|
393a40 |
- char *remote_queue, *remote_host;
|
|
|
393a40 |
+ char *remote_queue = NULL, *remote_host = NULL;
|
|
|
393a40 |
remote_printer_t *p;
|
|
|
393a40 |
- char *backup_queue_name, *local_queue_name = NULL;
|
|
|
393a40 |
- cups_dest_t *dests, *dest;
|
|
|
393a40 |
+ char *backup_queue_name = NULL, *local_queue_name = NULL;
|
|
|
393a40 |
+ cups_dest_t *dests = NULL, *dest = NULL;
|
|
|
393a40 |
int i, num_dests;
|
|
|
393a40 |
- const char *val;
|
|
|
393a40 |
+ size_t hl = 0;
|
|
|
393a40 |
+ const char *val = NULL;
|
|
|
393a40 |
|
|
|
393a40 |
/* This is a remote CUPS queue, find queue name and host name */
|
|
|
393a40 |
- remote_queue = resource + 9;
|
|
|
393a40 |
- remote_host = strdup(host);
|
|
|
393a40 |
- if (!strcmp(remote_host + strlen(remote_host) - 6, ".local"))
|
|
|
393a40 |
+ if (strncasecmp(resource, "printers/", 9)) {
|
|
|
393a40 |
+ debug_printf("cups-browsed: resource does not begin 'printers/'\n");
|
|
|
393a40 |
+ return;
|
|
|
393a40 |
+ }
|
|
|
393a40 |
+
|
|
|
393a40 |
+ remote_queue = remove_bad_chars(resource + 9, 0);
|
|
|
393a40 |
+ /* Find the remote host name.
|
|
|
393a40 |
+ * Used in constructing backup_queue_name, so need to sanitize.
|
|
|
393a40 |
+ * strdup() is called inside remove_bad_chars() and result is free()-able.
|
|
|
393a40 |
+ */
|
|
|
393a40 |
+ remote_host = remove_bad_chars(host, 1);
|
|
|
393a40 |
+ hl = strlen(remote_host);
|
|
|
393a40 |
+ if (hl > 6 && !strcmp(remote_host + strlen(remote_host) - 6, ".local"))
|
|
|
393a40 |
remote_host[strlen(remote_host) - 6] = '\0';
|
|
|
393a40 |
- if (!strcmp(remote_host + strlen(remote_host) - 7, ".local."))
|
|
|
393a40 |
+ if (hl > 7 && !strcmp(remote_host + strlen(remote_host) - 7, ".local."))
|
|
|
393a40 |
remote_host[strlen(remote_host) - 7] = '\0';
|
|
|
393a40 |
debug_printf("cups-browsed: Found CUPS queue: %s on host %s.\n",
|
|
|
393a40 |
remote_queue, remote_host);
|
|
|
393a40 |
@@ -592,7 +672,7 @@ void generate_local_queue(const char *ho
|
|
|
393a40 |
/* Check if there exists already a CUPS queue with the
|
|
|
393a40 |
requested name Try name@host in such a case and if
|
|
|
393a40 |
this is also taken, ignore the printer */
|
|
|
393a40 |
- if ((backup_queue_name = malloc((strlen(remote_queue) +
|
|
|
393a40 |
+ if ((backup_queue_name = malloc((strlen(remote_queue) +
|
|
|
393a40 |
strlen(remote_host) + 2) *
|
|
|
393a40 |
sizeof(char))) == NULL) {
|
|
|
393a40 |
debug_printf("cups-browsed: ERROR: Unable to allocate memory.\n");
|
|
|
393a40 |
@@ -639,6 +719,7 @@ void generate_local_queue(const char *ho
|
|
|
393a40 |
local_queue_name);
|
|
|
393a40 |
free (backup_queue_name);
|
|
|
393a40 |
free (remote_host);
|
|
|
393a40 |
+ free (remote_queue);
|
|
|
393a40 |
cupsFreeDests(num_dests, dests);
|
|
|
393a40 |
return;
|
|
|
393a40 |
}
|
|
|
393a40 |
@@ -724,6 +805,7 @@ void generate_local_queue(const char *ho
|
|
|
393a40 |
|
|
|
393a40 |
free (backup_queue_name);
|
|
|
393a40 |
free (remote_host);
|
|
|
393a40 |
+ free (remote_queue);
|
|
|
393a40 |
|
|
|
393a40 |
if (p)
|
|
|
393a40 |
debug_printf("cups-browsed: Bonjour IDs: Service name: \"%s\", "
|
|
|
393a40 |
@@ -958,12 +1040,18 @@ found_cups_printer (const char *remote_h
|
|
|
393a40 |
char local_resource[HTTP_MAX_URI];
|
|
|
393a40 |
char *c;
|
|
|
393a40 |
|
|
|
393a40 |
+ memset(scheme, 0, sizeof(scheme));
|
|
|
393a40 |
+ memset(username, 0, sizeof(username));
|
|
|
393a40 |
+ memset(host, 0, sizeof(host));
|
|
|
393a40 |
+ memset(resource, 0, sizeof(resource));
|
|
|
393a40 |
+ memset(local_resource, 0, sizeof(local_resource));
|
|
|
393a40 |
+
|
|
|
393a40 |
httpSeparateURI (HTTP_URI_CODING_ALL, uri,
|
|
|
393a40 |
- scheme, sizeof(scheme),
|
|
|
393a40 |
- username, sizeof(username),
|
|
|
393a40 |
- host, sizeof(host),
|
|
|
393a40 |
+ scheme, sizeof(scheme) - 1,
|
|
|
393a40 |
+ username, sizeof(username) - 1,
|
|
|
393a40 |
+ host, sizeof(host) - 1,
|
|
|
393a40 |
&port,
|
|
|
393a40 |
- resource, sizeof(resource));
|
|
|
393a40 |
+ resource, sizeof(resource)- 1);
|
|
|
393a40 |
|
|
|
393a40 |
/* Check this isn't one of our own broadcasts */
|
|
|
393a40 |
for (iface = cupsArrayFirst (netifs);
|
|
|
393a40 |
@@ -1071,7 +1159,12 @@ process_browse_data (GIOChannel *source,
|
|
|
393a40 |
char remote_host[256];
|
|
|
393a40 |
char uri[1024];
|
|
|
393a40 |
char info[1024];
|
|
|
393a40 |
- char *c;
|
|
|
393a40 |
+ char *c = NULL, *end = NULL;
|
|
|
393a40 |
+
|
|
|
393a40 |
+ memset(packet, 0, sizeof(packet));
|
|
|
393a40 |
+ memset(remote_host, 0, sizeof(remote_host));
|
|
|
393a40 |
+ memset(uri, 0, sizeof(uri));
|
|
|
393a40 |
+ memset(info, 0, sizeof(info));
|
|
|
393a40 |
|
|
|
393a40 |
srclen = sizeof (srcaddr);
|
|
|
393a40 |
got = recvfrom (browsesocket, packet, sizeof (packet) - 1, 0,
|
|
|
393a40 |
@@ -1084,7 +1177,7 @@ process_browse_data (GIOChannel *source,
|
|
|
393a40 |
}
|
|
|
393a40 |
|
|
|
393a40 |
packet[got] = '\0';
|
|
|
393a40 |
- httpAddrString (&srcaddr, remote_host, sizeof (remote_host));
|
|
|
393a40 |
+ httpAddrString (&srcaddr, remote_host, sizeof (remote_host) - 1);
|
|
|
393a40 |
|
|
|
393a40 |
/* Check this packet is allowed */
|
|
|
393a40 |
if (!allowed ((struct sockaddr *) &srcaddr)) {
|
|
|
393a40 |
@@ -1102,28 +1195,42 @@ process_browse_data (GIOChannel *source,
|
|
|
393a40 |
}
|
|
|
393a40 |
|
|
|
393a40 |
info[0] = '\0';
|
|
|
393a40 |
+
|
|
|
393a40 |
+ /* do not read OOB */
|
|
|
393a40 |
+ end = packet + sizeof(packet);
|
|
|
393a40 |
c = strchr (packet, '\"');
|
|
|
393a40 |
+ if (c >= end)
|
|
|
393a40 |
+ return TRUE;
|
|
|
393a40 |
+
|
|
|
393a40 |
if (c) {
|
|
|
393a40 |
/* Skip location field */
|
|
|
393a40 |
- for (c++; *c != '\"'; c++)
|
|
|
393a40 |
+ for (c++; c < end && *c != '\"'; c++)
|
|
|
393a40 |
;
|
|
|
393a40 |
|
|
|
393a40 |
+ if (c >= end)
|
|
|
393a40 |
+ return TRUE;
|
|
|
393a40 |
+
|
|
|
393a40 |
if (*c == '\"') {
|
|
|
393a40 |
- for (c++; isspace(*c); c++)
|
|
|
393a40 |
+ for (c++; c < end && isspace(*c); c++)
|
|
|
393a40 |
;
|
|
|
393a40 |
}
|
|
|
393a40 |
|
|
|
393a40 |
+ if (c >= end)
|
|
|
393a40 |
+ return TRUE;
|
|
|
393a40 |
+
|
|
|
393a40 |
/* Is there an info field? */
|
|
|
393a40 |
if (*c == '\"') {
|
|
|
393a40 |
int i;
|
|
|
393a40 |
c++;
|
|
|
393a40 |
for (i = 0;
|
|
|
393a40 |
- i < sizeof (info) - 1 && *c != '\"';
|
|
|
393a40 |
+ i < sizeof (info) - 1 && *c != '\"' && c < end;
|
|
|
393a40 |
i++, c++)
|
|
|
393a40 |
info[i] = *c;
|
|
|
393a40 |
info[i] = '\0';
|
|
|
393a40 |
}
|
|
|
393a40 |
}
|
|
|
393a40 |
+ if (c >= end)
|
|
|
393a40 |
+ return TRUE;
|
|
|
393a40 |
|
|
|
393a40 |
found_cups_printer (remote_host, uri, info);
|
|
|
393a40 |
recheck_timer ();
|
|
|
393a40 |
@@ -1332,7 +1439,7 @@ send_browse_data (gpointer data)
|
|
|
393a40 |
while (attr && ippGetGroupTag(attr) == IPP_TAG_PRINTER) {
|
|
|
393a40 |
const char *attrname = ippGetName(attr);
|
|
|
393a40 |
int value_tag = ippGetValueTag(attr);
|
|
|
393a40 |
-
|
|
|
393a40 |
+
|
|
|
393a40 |
if (!strcmp(attrname, "printer-type") &&
|
|
|
393a40 |
value_tag == IPP_TAG_ENUM) {
|
|
|
393a40 |
type = ippGetInteger(attr, 0);
|