From: Nicolas Thill Date: Fri, 24 Apr 2009 12:07:08 +0000 (+0000) Subject: [packages] cups: add a bunch of security fixes in 8.09 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=8992fd83268b9c08456ecf966b87511518d12eee;p=openwrt%2Fsvn-archive%2Farchive.git [packages] cups: add a bunch of security fixes in 8.09 SVN-Revision: 15379 --- diff --git a/net/cups/patches/901-cve-2008-1722.patch b/net/cups/patches/901-cve-2008-1722.patch new file mode 100644 index 0000000000..8fca14c4e3 --- /dev/null +++ b/net/cups/patches/901-cve-2008-1722.patch @@ -0,0 +1,72 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-1722 + +--- a/filter/image-png.c ++++ b/filter/image-png.c +@@ -3,7 +3,7 @@ + * + * PNG image routines for the Common UNIX Printing System (CUPS). + * +- * Copyright 2007 by Apple Inc. ++ * Copyright 2007-2008 by Apple Inc. + * Copyright 1993-2007 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the +@@ -170,16 +170,56 @@ _cupsImageReadPNG( + * Interlaced images must be loaded all at once... + */ + ++ size_t bufsize; /* Size of buffer */ ++ ++ + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) +- in = malloc(img->xsize * img->ysize); ++ { ++ bufsize = img->xsize * img->ysize; ++ ++ if ((bufsize / img->ysize) != img->xsize) ++ { ++ fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", ++ (unsigned)width, (unsigned)height); ++ fclose(fp); ++ return (1); ++ } ++ } + else +- in = malloc(img->xsize * img->ysize * 3); ++ { ++ bufsize = img->xsize * img->ysize * 3; ++ ++ if ((bufsize / (img->ysize * 3)) != img->xsize) ++ { ++ fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", ++ (unsigned)width, (unsigned)height); ++ fclose(fp); ++ return (1); ++ } ++ } ++ ++ in = malloc(bufsize); + } + + bpp = cupsImageGetDepth(img); + out = malloc(img->xsize * bpp); + ++ if (!in || !out) ++ { ++ fputs("DEBUG: Unable to allocate memory for PNG image!\n", stderr); ++ ++ if (in) ++ free(in); ++ ++ if (out) ++ free(out); ++ ++ fclose(fp); ++ ++ return (1); ++ } ++ + /* + * Read the image, interlacing as needed... + */ diff --git a/net/cups/patches/902-cve-2008-3639.patch b/net/cups/patches/902-cve-2008-3639.patch new file mode 100644 index 0000000000..591076133b --- /dev/null +++ b/net/cups/patches/902-cve-2008-3639.patch @@ -0,0 +1,40 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-3639 + +--- a/filter/image-sgilib.c ++++ b/filter/image-sgilib.c +@@ -640,13 +640,14 @@ read_rle8(FILE *fp, /* I - Fi + if (ch & 128) + { + for (i = 0; i < count; i ++, row ++, xsize --, length ++) +- *row = getc(fp); ++ if (xsize > 0) ++ *row = getc(fp); + } + else + { + ch = getc(fp); + length ++; +- for (i = 0; i < count; i ++, row ++, xsize --) ++ for (i = 0; i < count && xsize > 0; i ++, row ++, xsize --) + *row = ch; + } + } +@@ -685,14 +686,15 @@ read_rle16(FILE *fp, /* I - F + if (ch & 128) + { + for (i = 0; i < count; i ++, row ++, xsize --, length ++) +- *row = getshort(fp); ++ if (xsize > 0) ++ *row = getshort(fp); + } + else + { + ch = getshort(fp); + length ++; +- for (i = 0; i < count; i ++, row ++, xsize --) +- *row = ch; ++ for (i = 0; i < count && xsize > 0; i ++, row ++, xsize --) ++ *row = ch; + } + } + diff --git a/net/cups/patches/903-cve-2008-3640.patch b/net/cups/patches/903-cve-2008-3640.patch new file mode 100644 index 0000000000..6f218b90b1 --- /dev/null +++ b/net/cups/patches/903-cve-2008-3640.patch @@ -0,0 +1,83 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-3640 + +--- a/filter/textcommon.c ++++ b/filter/textcommon.c +@@ -3,7 +3,7 @@ + * + * Common text filter routines for the Common UNIX Printing System (CUPS). + * +- * Copyright 2007 by Apple Inc. ++ * Copyright 2007-2008 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the +@@ -605,14 +605,38 @@ TextMain(const char *name, /* I - Name o + !strcasecmp(val, "yes"); + + if ((val = cupsGetOption("columns", num_options, options)) != NULL) ++ { + PageColumns = atoi(val); + ++ if (PageColumns < 1) ++ { ++ _cupsLangPrintf(stderr, _("ERROR: Bad columns value %d!\n"), PageColumns); ++ return (1); ++ } ++ } ++ + if ((val = cupsGetOption("cpi", num_options, options)) != NULL) ++ { + CharsPerInch = atof(val); + ++ if (CharsPerInch <= 0.0) ++ { ++ _cupsLangPrintf(stderr, _("ERROR: Bad cpi value %f!\n"), CharsPerInch); ++ return (1); ++ } ++ } ++ + if ((val = cupsGetOption("lpi", num_options, options)) != NULL) ++ { + LinesPerInch = atof(val); + ++ if (LinesPerInch <= 0.0) ++ { ++ _cupsLangPrintf(stderr, _("ERROR: Bad lpi value %f!\n"), LinesPerInch); ++ return (1); ++ } ++ } ++ + if (PrettyPrint) + PageTop -= 216.0f / LinesPerInch; + +--- a/filter/texttops.c ++++ b/filter/texttops.c +@@ -173,6 +173,14 @@ WriteProlog(const char *title, /* I - T + SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch; + SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch; + ++ if (SizeColumns <= 0 || SizeColumns > 32767 || ++ SizeLines <= 0 || SizeLines > 32767) ++ { ++ _cupsLangPrintf(stderr, _("ERROR: Unable to print %dx%d text page!\n"), ++ SizeColumns, SizeLines); ++ exit(1); ++ } ++ + Page = calloc(sizeof(lchar_t *), SizeLines); + Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines); + for (i = 1; i < SizeLines; i ++) +@@ -187,6 +195,13 @@ WriteProlog(const char *title, /* I - T + else + ColumnWidth = SizeColumns; + ++ if (ColumnWidth <= 0) ++ { ++ _cupsLangPrintf(stderr, _("ERROR: Unable to print %d text columns!\n"), ++ PageColumns); ++ exit(1); ++ } ++ + /* + * Output the DSC header... + */ diff --git a/net/cups/patches/904-cve-2008-3641.patch b/net/cups/patches/904-cve-2008-3641.patch new file mode 100644 index 0000000000..97addd4856 --- /dev/null +++ b/net/cups/patches/904-cve-2008-3641.patch @@ -0,0 +1,129 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-3641 + +--- a/filter/hpgl-attr.c ++++ b/filter/hpgl-attr.c +@@ -197,8 +197,18 @@ NP_number_pens(int num_params, /* I + + if (num_params == 0) + PenCount = 8; +- else if (num_params == 1 && params[0].value.number <= 1024) +- PenCount = (int)params[0].value.number; ++ else if (num_params == 1) ++ { ++ if (params[0].value.number < 1 || params[0].value.number > MAX_PENS) ++ { ++ fprintf(stderr, ++ "DEBUG: HP-GL/2 \'NP\' command with invalid number of " ++ "pens (%d)!\n", (int)params[0].value.number); ++ PenCount = 8; ++ } ++ else ++ PenCount = (int)params[0].value.number; ++ } + else + fprintf(stderr, + "DEBUG: HP-GL/2 \'NP\' command with invalid number of " +@@ -235,7 +245,7 @@ PC_pen_color(int num_params, /* I - + + if (num_params == 0) + { +- for (i = 0; i <= PenCount; i ++) ++ for (i = 0; i < PenCount; i ++) + if (i < 8) + { + Pens[i].rgb[0] = standard_colors[i][0]; +@@ -256,7 +266,14 @@ PC_pen_color(int num_params, /* I - + } + else if (num_params == 1 || num_params == 4) + { +- i = (int)params[0].value.number; ++ i = (int)params[0].value.number - 1; ++ ++ if (i < 0 || i >= PenCount) ++ { ++ fprintf(stderr, ++ "DEBUG: HP-GL/2 \'PC\' command with invalid pen (%d)!\n", i + 1); ++ return; ++ } + + if (num_params == 1) + { +@@ -330,7 +347,15 @@ PW_pen_width(int num_params, /* I - + + if (num_params == 2) + { +- pen = (int)params[1].value.number; ++ pen = (int)params[1].value.number - 1; ++ ++ if (pen < 0 || pen >= PenCount) ++ { ++ fprintf(stderr, ++ "DEBUG: HP-GL/2 \'PW\' command with invalid pen (%d)!\n", ++ pen + 1); ++ return; ++ } + + Pens[pen].width = w; + +@@ -345,7 +370,7 @@ PW_pen_width(int num_params, /* I - + * Set width for all pens... + */ + +- for (pen = 0; pen <= PenCount; pen ++) ++ for (pen = 0; pen < PenCount; pen ++) + Pens[pen].width = w; + + if (PageDirty) +@@ -399,14 +424,16 @@ SP_select_pen(int num_params, /* I - + param_t *params) /* I - Parameters */ + { + if (num_params == 0) +- PenNumber = 1; +- else if (params[0].value.number <= PenCount) +- PenNumber = (int)params[0].value.number; +- else ++ PenNumber = 0; ++ else if (num_params > 1) + fprintf(stderr, +- "DEBUG: HP-GL/2 \'SP\' command with invalid number or value " +- "of parameters (%d, %d)!\n", num_params, ++ "DEBUG: HP-GL/2 \'SP\' command with invalid number of parameters " ++ "(%d)!\n", num_params); ++ else if (params[0].value.number <= 0 || params[0].value.number >= PenCount) ++ fprintf(stderr, "DEBUG: HP-GL/2 \'SP\' command with invalid pen (%d)!\n", + (int)params[0].value.number); ++ else ++ PenNumber = (int)params[0].value.number - 1; + + if (PageDirty) + printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], +--- a/filter/hpgltops.h ++++ b/filter/hpgltops.h +@@ -26,6 +26,14 @@ + # define M_PI 3.14159265358979323846 + #endif /* M_PI */ + ++ ++/* ++ * Maximum number of pens we emulate... ++ */ ++ ++#define MAX_PENS 1024 ++ ++ + /* + * Parameter value structure... + */ +@@ -108,10 +116,10 @@ VAR float PenPosition[2] VALUE2(0.0f, 0. + /* Current pen position */ + PenScaling VALUE(1.0f), /* Pen width scaling factor */ + PenWidth VALUE(1.0f); /* Default pen width */ +-VAR pen_t Pens[1024]; /* State of each pen */ ++VAR pen_t Pens[MAX_PENS]; /* State of each pen */ + VAR int PenMotion VALUE(0), /* 0 = absolute, 1 = relative */ + PenValid VALUE(0), /* 1 = valid position, 0 = undefined */ +- PenNumber VALUE(1), /* Current pen number */ ++ PenNumber VALUE(0), /* Current pen number */ + PenCount VALUE(8), /* Number of pens */ + PenDown VALUE(0), /* 0 = pen up, 1 = pen down */ + PolygonMode VALUE(0), /* Drawing polygons? */ diff --git a/net/cups/patches/905-cve-2008-5183.patch b/net/cups/patches/905-cve-2008-5183.patch new file mode 100644 index 0000000000..611312cc35 --- /dev/null +++ b/net/cups/patches/905-cve-2008-5183.patch @@ -0,0 +1,168 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5183 + +--- a/scheduler/ipp.c ++++ b/scheduler/ipp.c +@@ -2027,24 +2027,25 @@ add_job_subscriptions( + if (mask == CUPSD_EVENT_NONE) + mask = CUPSD_EVENT_JOB_COMPLETED; + +- sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job, recipient, +- 0); ++ if ((sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job, ++ recipient, 0)) != NULL) ++ { ++ sub->interval = interval; + +- sub->interval = interval; ++ cupsdSetString(&sub->owner, job->username); + +- cupsdSetString(&sub->owner, job->username); ++ if (user_data) ++ { ++ sub->user_data_len = user_data->values[0].unknown.length; ++ memcpy(sub->user_data, user_data->values[0].unknown.data, ++ sub->user_data_len); ++ } + +- if (user_data) +- { +- sub->user_data_len = user_data->values[0].unknown.length; +- memcpy(sub->user_data, user_data->values[0].unknown.data, +- sub->user_data_len); ++ ippAddSeparator(con->response); ++ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, ++ "notify-subscription-id", sub->id); + } + +- ippAddSeparator(con->response); +- ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, +- "notify-subscription-id", sub->id); +- + if (attr) + attr = attr->next; + } +@@ -5417,7 +5418,12 @@ create_subscription( + else + job = NULL; + +- sub = cupsdAddSubscription(mask, printer, job, recipient, 0); ++ if ((sub = cupsdAddSubscription(mask, printer, job, recipient, 0)) == NULL) ++ { ++ send_ipp_status(con, IPP_TOO_MANY_SUBSCRIPTIONS, ++ _("There are too many subscriptions.")); ++ return; ++ } + + if (job) + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d", +--- a/scheduler/subscriptions.c ++++ b/scheduler/subscriptions.c +@@ -341,8 +341,54 @@ cupsdAddSubscription( + * Limit the number of subscriptions... + */ + +- if (cupsArrayCount(Subscriptions) >= MaxSubscriptions) ++ if (MaxSubscriptions > 0 && cupsArrayCount(Subscriptions) >= MaxSubscriptions) ++ { ++ cupsdLogMessage(CUPSD_LOG_DEBUG, ++ "cupsdAddSubscription: Reached MaxSubscriptions %d", ++ MaxSubscriptions); + return (NULL); ++ } ++ ++ if (MaxSubscriptionsPerJob > 0 && job) ++ { ++ int count; /* Number of job subscriptions */ ++ ++ for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), ++ count = 0; ++ temp; ++ temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) ++ if (temp->job == job) ++ count ++; ++ ++ if (count >= MaxSubscriptionsPerJob) ++ { ++ cupsdLogMessage(CUPSD_LOG_DEBUG, ++ "cupsdAddSubscription: Reached MaxSubscriptionsPerJob %d " ++ "for job #%d", MaxSubscriptionsPerJob, job->id); ++ return (NULL); ++ } ++ } ++ ++ if (MaxSubscriptionsPerPrinter > 0 && dest) ++ { ++ int count; /* Number of printer subscriptions */ ++ ++ for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), ++ count = 0; ++ temp; ++ temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) ++ if (temp->dest == dest) ++ count ++; ++ ++ if (count >= MaxSubscriptionsPerPrinter) ++ { ++ cupsdLogMessage(CUPSD_LOG_DEBUG, ++ "cupsdAddSubscription: Reached " ++ "MaxSubscriptionsPerPrinter %d for %s", ++ MaxSubscriptionsPerPrinter, dest->name); ++ return (NULL); ++ } ++ } + + /* + * Allocate memory for this subscription... +@@ -758,7 +804,6 @@ cupsdLoadAllSubscriptions(void) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); +- break; + } + else if (!strcasecmp(line, "Events")) + { +--- a/test/4.4-subscription-ops.test ++++ b/test/4.4-subscription-ops.test +@@ -116,6 +116,32 @@ + EXPECT notify-events + DISPLAY notify-events + } ++{ ++ # The name of the test... ++ NAME "Check MaxSubscriptions limits" ++ ++ # The operation to use ++ OPERATION Create-Printer-Subscription ++ RESOURCE / ++ ++ # The attributes to send ++ GROUP operation ++ ATTR charset attributes-charset utf-8 ++ ATTR language attributes-natural-language en ++ ATTR uri printer-uri $method://$hostname:$port/printers/Test1 ++ ++ GROUP subscription ++ ATTR uri notify-recipient-uri testnotify:// ++ ATTR keyword notify-events printer-state-changed ++ ATTR integer notify-lease-duration 5 ++ ++ # What statuses are OK? ++ STATUS client-error-too-many-subscriptions ++ ++ # What attributes do we expect? ++ EXPECT attributes-charset ++ EXPECT attributes-natural-language ++} + + # + # End of "$Id: 4.4-subscription-ops.test 6635 2007-07-09 20:34:48Z mike $" +--- a/test/run-stp-tests.sh ++++ b/test/run-stp-tests.sh +@@ -303,6 +303,7 @@ FontPath /tmp/cups-$user/share/fonts + DocumentRoot $root/doc + RequestRoot /tmp/cups-$user/spool + TempDir /tmp/cups-$user/spool/temp ++MaxSubscriptions 3 + MaxLogSize 0 + AccessLog /tmp/cups-$user/log/access_log + ErrorLog /tmp/cups-$user/log/error_log diff --git a/net/cups/patches/906-cve-2008-5184.patch b/net/cups/patches/906-cve-2008-5184.patch new file mode 100644 index 0000000000..b2fa47fdff --- /dev/null +++ b/net/cups/patches/906-cve-2008-5184.patch @@ -0,0 +1,58 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5184 + +--- a/cgi-bin/admin.c ++++ b/cgi-bin/admin.c +@@ -309,6 +309,16 @@ do_add_rss_subscription(http_t *http) /* + } + + /* ++ * Make sure we have a username... ++ */ ++ ++ if ((user = getenv("REMOTE_USER")) == NULL) ++ { ++ puts("Status: 401\n"); ++ exit(0); ++ } ++ ++ /* + * Validate the subscription name... + */ + +@@ -352,9 +362,6 @@ do_add_rss_subscription(http_t *http) /* + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, printer_uri); + +- if ((user = getenv("REMOTE_USER")) == NULL) +- user = "guest"; +- + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, user); + +@@ -1269,6 +1276,16 @@ do_cancel_subscription(http_t *http)/* I + } + + /* ++ * Require a username... ++ */ ++ ++ if ((user = getenv("REMOTE_USER")) == NULL) ++ { ++ puts("Status: 401\n"); ++ exit(0); ++ } ++ ++ /* + * Cancel the subscription... + */ + +@@ -1279,9 +1296,6 @@ do_cancel_subscription(http_t *http)/* I + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, + "notify-subscription-id", id); + +- if ((user = getenv("REMOTE_USER")) == NULL) +- user = "guest"; +- + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, user); + diff --git a/net/cups/patches/907-cve-2008-5286.patch b/net/cups/patches/907-cve-2008-5286.patch new file mode 100644 index 0000000000..0c077923ca --- /dev/null +++ b/net/cups/patches/907-cve-2008-5286.patch @@ -0,0 +1,22 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5286 + +--- a/filter/image-png.c ++++ b/filter/image-png.c +@@ -178,7 +178,7 @@ _cupsImageReadPNG( + { + bufsize = img->xsize * img->ysize; + +- if ((bufsize / img->ysize) != img->xsize) ++ if ((bufsize / img->xsize) != img->ysize) + { + fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", + (unsigned)width, (unsigned)height); +@@ -190,7 +190,7 @@ _cupsImageReadPNG( + { + bufsize = img->xsize * img->ysize * 3; + +- if ((bufsize / (img->ysize * 3)) != img->xsize) ++ if ((bufsize / (img->xsize * 3)) != img->ysize) + { + fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", + (unsigned)width, (unsigned)height); diff --git a/net/cups/patches/908-cve-2009-0163.patch b/net/cups/patches/908-cve-2009-0163.patch new file mode 100644 index 0000000000..ccf5769e9c --- /dev/null +++ b/net/cups/patches/908-cve-2009-0163.patch @@ -0,0 +1,15 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0163 + +--- a/filter/image-private.h ++++ b/filter/image-private.h +@@ -41,8 +41,8 @@ + + # define CUPS_IMAGE_MAX_WIDTH 0x07ffffff + /* 2^27-1 to allow for 15-channel data */ +-# define CUPS_IMAGE_MAX_HEIGHT 0x7fffffff +- /* 2^31-1 */ ++# define CUPS_IMAGE_MAX_HEIGHT 0x3fffffff ++ /* 2^30-1 */ + + # define CUPS_TILE_SIZE 256 /* 256x256 pixel tiles */ + # define CUPS_TILE_MINIMUM 10 /* Minimum number of tiles */ diff --git a/net/cups/patches/909-cve-2009-0164.patch b/net/cups/patches/909-cve-2009-0164.patch new file mode 100644 index 0000000000..0cbd067f3d --- /dev/null +++ b/net/cups/patches/909-cve-2009-0164.patch @@ -0,0 +1,575 @@ +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0164 + +--- a/cups/http-addr.c ++++ b/cups/http-addr.c +@@ -149,7 +149,7 @@ httpAddrLocalhost( + #endif /* AF_LOCAL */ + + if (addr->addr.sa_family == AF_INET && +- ntohl(addr->ipv4.sin_addr.s_addr) == 0x7f000001) ++ (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000) + return (1); + + return (0); +--- a/doc/help/ref-cupsd-conf.html.in ++++ b/doc/help/ref-cupsd-conf.html.in +@@ -2477,6 +2477,37 @@ administrator email address is roo + HREF="#ServerName">ServerName.

+ + ++

CUPS 1.3.10ServerAlias

++ ++

Examples

++ ++
++ServerAlias althost
++ServerAlias althost.foo.com
++ServerAlias althost.bar.com
++ServerAlias *
++
++ ++

Description

++ ++

The ServerAlias directive specifies alternate names that the ++server is known by. By default it contains a list of all aliases associated ++with the ServerName. The special name ++"*" can be used to allow any hostname when accessing CUPS via an external ++network interfaces.

++ ++
Note ++ ++

The ServerAlias directive is used for HTTP Host header ++validation when clients connect to the scheduler from external interfaces. ++Using the special name "*" can expose your system to known browser-based ++DNS rebinding attacks, even when accessing sites through a firewall. If the ++auto-discovery of alternate names does not work, we recommend listing each ++alternate name with a ServerAlias directive instead of using "*".

++ ++
++ ++ +

ServerBin

+ +

Examples

+--- a/man/cupsd.conf.man.in ++++ b/man/cupsd.conf.man.in +@@ -540,6 +540,11 @@ ServerAdmin user@domain.com + .br + Specifies the email address of the server administrator. + .TP 5 ++ServerAlias hostname ++.br ++Specifies an alternate name that the server is known by. The special name "*" ++allows any name to be used. ++.TP 5 + ServerBin directory + .br + Specifies the directory where backends, CGIs, daemons, and filters may +--- a/scheduler/client.c ++++ b/scheduler/client.c +@@ -100,6 +100,7 @@ static int make_certificate(cupsd_clien + #endif /* HAVE_SSL */ + static int pipe_command(cupsd_client_t *con, int infile, int *outfile, + char *command, char *options, int root); ++static int valid_host(cupsd_client_t *con); + static int write_file(cupsd_client_t *con, http_status_t code, + char *filename, char *type, + struct stat *filestats); +@@ -259,16 +260,7 @@ cupsdAcceptClient(cupsd_listener_t *lis) + * Map accesses from the same host to the server name. + */ + +- for (addr = ServerAddrs; addr; addr = addr->next) +- if (httpAddrEqual(con->http.hostaddr, &(addr->addr))) +- break; +- +- if (addr) +- { +- strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname)); +- hostname = con->http.hostname; +- } +- else if (HostNameLookups) ++ if (HostNameLookups) + hostname = httpAddrLookup(con->http.hostaddr, con->http.hostname, + sizeof(con->http.hostname)); + else +@@ -1066,6 +1058,23 @@ cupsdReadClient(cupsd_client_t *con) /* + return; + } + } ++ else if (!valid_host(con)) ++ { ++ /* ++ * Access to localhost must use "localhost" or the corresponding IPv4 ++ * or IPv6 values in the Host: field. ++ */ ++ ++ cupsdLogMessage(CUPSD_LOG_WARN, ++ "Request from \"%s\" using invalid Host: field \"%s\"", ++ con->http.hostname, con->http.fields[HTTP_FIELD_HOST]); ++ ++ if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE)) ++ { ++ cupsdCloseClient(con); ++ return; ++ } ++ } + else if (con->operation == HTTP_OPTIONS) + { + /* +@@ -4760,6 +4769,137 @@ pipe_command(cupsd_client_t *con, /* I - + + + /* ++ * 'valid_host()' - Is the Host: field valid? ++ */ ++ ++static int /* O - 1 if valid, 0 if not */ ++valid_host(cupsd_client_t *con) /* I - Client connection */ ++{ ++ cupsd_alias_t *a; /* Current alias */ ++ cupsd_netif_t *netif; /* Current network interface */ ++ const char *host, /* Host field */ ++ *end; /* End character */ ++ ++ ++ host = con->http.fields[HTTP_FIELD_HOST]; ++ ++ if (httpAddrLocalhost(con->http.hostaddr)) ++ { ++ /* ++ * Only allow "localhost" or the equivalent IPv4 or IPv6 numerical ++ * addresses when accessing CUPS via the loopback interface... ++ */ ++ ++ return (!strcasecmp(host, "localhost") || ++ !strncasecmp(host, "localhost:", 10) || ++ !strcasecmp(host, "localhost.") || ++ !strncasecmp(host, "localhost.:", 11) || ++#ifdef __linux ++ !strcasecmp(host, "localhost.localdomain") || ++ !strncasecmp(host, "localhost.localdomain:", 22) || ++#endif /* __linux */ ++ !strcmp(host, "127.0.0.1") || ++ !strncmp(host, "127.0.0.1:", 10) || ++ !strcmp(host, "[::1]") || ++ !strncmp(host, "[::1]:", 6)); ++ } ++ ++#ifdef HAVE_DNSSD ++ /* ++ * Check if the hostname is something.local (Bonjour); if so, allow it. ++ */ ++ ++ if ((end = strrchr(host, '.')) != NULL && ++ (!strcasecmp(end, ".local") || !strncasecmp(end, ".local:", 7))) ++ return (1); ++#endif /* HAVE_DNSSD */ ++ ++ /* ++ * Check for (alias) name matches... ++ */ ++ ++ for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias); ++ a; ++ a = (cupsd_alias_t *)cupsArrayNext(ServerAlias)) ++ { ++ /* ++ * "ServerAlias *" allows all host values through... ++ */ ++ ++ if (!strcmp(a->name, "*")) ++ return (1); ++ ++ if (!strncasecmp(host, a->name, a->namelen)) ++ { ++ /* ++ * Prefix matches; check the character at the end - it must be either ++ * ":" or nul... ++ */ ++ ++ end = host + a->namelen; ++ ++ if (!*end || *end == ':') ++ return (1); ++ } ++ } ++ ++ /* ++ * Check for interface hostname matches... ++ */ ++ ++ for (netif = (cupsd_netif_t *)cupsArrayFirst(NetIFList); ++ netif; ++ netif = (cupsd_netif_t *)cupsArrayNext(NetIFList)) ++ { ++ if (!strncasecmp(host, netif->hostname, netif->hostlen)) ++ { ++ /* ++ * Prefix matches; check the character at the end - it must be either ++ * ":" or nul... ++ */ ++ ++ end = host + netif->hostlen; ++ ++ if (!*end || *end == ':') ++ return (1); ++ } ++ } ++ ++ /* ++ * Check if the hostname is an IP address... ++ */ ++ ++ if (isdigit(*host & 255) || *host == '[') ++ { ++ /* ++ * Possible IPv4/IPv6 address... ++ */ ++ ++ char temp[1024], /* Temporary string */ ++ *ptr; /* Pointer into temporary string */ ++ http_addrlist_t *addrlist; /* List of addresses */ ++ ++ ++ strlcpy(temp, host, sizeof(temp)); ++ if ((ptr = strrchr(temp, ':')) != NULL && !strchr(ptr, ']')) ++ *ptr = '\0'; /* Strip :port from host value */ ++ ++ if ((addrlist = httpAddrGetList(temp, AF_UNSPEC, NULL)) != NULL) ++ { ++ /* ++ * Good IPv4/IPv6 address... ++ */ ++ ++ httpAddrFreeList(addrlist); ++ return (1); ++ } ++ } ++ ++ return (0); ++} ++ ++ ++/* + * 'write_file()' - Send a file via HTTP. + */ + +--- a/scheduler/client.h ++++ b/scheduler/client.h +@@ -95,8 +95,6 @@ VAR time_t ListeningPaused VALUE(0); + /* Time when listening was paused */ + VAR cups_array_t *Clients VALUE(NULL); + /* HTTP clients */ +-VAR http_addrlist_t *ServerAddrs VALUE(NULL); +- /* Server address(es) */ + VAR char *ServerHeader VALUE(NULL); + /* Server header in requests */ + VAR int CGIPipes[2] VALUE2(-1,-1); +--- a/scheduler/conf.c ++++ b/scheduler/conf.c +@@ -187,6 +187,9 @@ static const unsigned zeros[4] = + /* + * Local functions... + */ ++ ++static void add_alias(const char *name); ++static void free_aliases(void); + static http_addrlist_t *get_address(const char *value, int defport); + static int get_addr_and_mask(const char *value, unsigned *ip, + unsigned *mask); +@@ -253,7 +256,8 @@ cupsdCheckPermissions( + return (-1); + } + +- dir_created = 1; ++ dir_created = 1; ++ fileinfo.st_mode = mode | S_IFDIR; + } + else + return (create_dir ? -1 : 1); +@@ -395,12 +399,16 @@ cupsdReadConfiguration(void) + + cupsdDeleteAllListeners(); + ++ RemoteAccessEnabled = 0; ++ + /* + * String options... + */ + +- cupsdSetString(&ServerName, httpGetHostname(NULL, temp, sizeof(temp))); +- cupsdSetStringf(&ServerAdmin, "root@%s", temp); ++ free_aliases(); ++ ++ cupsdClearString(&ServerName); ++ cupsdClearString(&ServerAdmin); + cupsdSetString(&ServerBin, CUPS_SERVERBIN); + cupsdSetString(&RequestRoot, CUPS_REQUESTS); + cupsdSetString(&CacheDir, CUPS_CACHEDIR); +@@ -608,15 +616,69 @@ cupsdReadConfiguration(void) + + RunUser = getuid(); + ++ cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.", ++ RemoteAccessEnabled ? "enabled" : "disabled"); ++ + /* + * See if the ServerName is an IP address... + */ + ++ if (!ServerName) ++ { ++ if (gethostname(temp, sizeof(temp))) ++ { ++ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get hostname: %s", ++ strerror(errno)); ++ strlcpy(temp, "localhost", sizeof(temp)); ++ } ++ ++ cupsdSetString(&ServerName, temp); ++ add_alias(temp); ++ ++ if (HostNameLookups || RemoteAccessEnabled) ++ { ++ struct hostent *host; /* Host entry to get FQDN */ ++ ++ if ((host = gethostbyname(temp)) != NULL) ++ { ++ if (strcasecmp(temp, host->h_name)) ++ { ++ cupsdSetString(&ServerName, host->h_name); ++ add_alias(host->h_name); ++ } ++ ++ if (host->h_aliases) ++ { ++ for (i = 0; host->h_aliases[i]; i ++) ++ if (strcasecmp(temp, host->h_aliases[i])) ++ add_alias(host->h_aliases[i]); ++ } ++ } ++ } ++ ++ /* ++ * Make sure we have the base hostname added as an alias, too! ++ */ ++ ++ if ((slash = strchr(temp, '.')) != NULL) ++ { ++ *slash = '\0'; ++ add_alias(temp); ++ } ++ } ++ + for (slash = ServerName; isdigit(*slash & 255) || *slash == '.'; slash ++); + + ServerNameIsIP = !*slash; + + /* ++ * Make sure ServerAdmin is initialized... ++ */ ++ ++ if (!ServerAdmin) ++ cupsdSetStringf(&ServerAdmin, "root@%s", ServerName); ++ ++ /* + * Use the default system group if none was supplied in cupsd.conf... + */ + +@@ -1227,6 +1289,52 @@ cupsdReadConfiguration(void) + + + /* ++ * 'add_alias()' - Add a ServerAlias. ++ */ ++ ++static void ++add_alias(const char *name) /* I - Name to add */ ++{ ++ cupsd_alias_t *a; /* New alias */ ++ size_t namelen; /* Length of name */ ++ ++ ++ namelen = strlen(name); ++ ++ if ((a = (cupsd_alias_t *)malloc(sizeof(cupsd_alias_t) + namelen)) == NULL) ++ return; ++ ++ if (!ServerAlias) ++ ServerAlias = cupsArrayNew(NULL, NULL); ++ ++ a->namelen = namelen; ++ strcpy(a->name, name); /* OK since a->name is allocated */ ++ ++ cupsArrayAdd(ServerAlias, a); ++} ++ ++ ++/* ++ * 'free_aliases()' - Free all of the ServerAlias entries. ++ */ ++ ++static void ++free_aliases(void) ++{ ++ cupsd_alias_t *a; /* Current alias */ ++ ++ ++ for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias); ++ a; ++ a = (cupsd_alias_t *)cupsArrayNext(ServerAlias)) ++ free(a); ++ ++ cupsArrayDelete(ServerAlias); ++ ServerAlias = NULL; ++} ++ ++ ++/* + * 'get_address()' - Get an address + port number from a line. + */ + +@@ -2260,6 +2368,9 @@ read_configuration(cups_file_t *fp) /* I + #endif /* AF_LOCAL */ + cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv4)", temp, + ntohs(lis->address.ipv4.sin_port)); ++ ++ if (!httpAddrLocalhost(&(lis->address))) ++ RemoteAccessEnabled = 1; + } + + /* +@@ -2993,6 +3104,8 @@ read_configuration(cups_file_t *fp) /* I + break; + } + } ++ else if (!strcasecmp(line, "ServerAlias")) ++ add_alias(value); + else if (!strcasecmp(line, "SetEnv")) + { + /* +--- a/scheduler/conf.h ++++ b/scheduler/conf.h +@@ -46,6 +46,17 @@ typedef enum + + + /* ++ * ServerAlias data... ++ */ ++ ++typedef struct ++{ ++ size_t namelen; /* Length of alias name */ ++ char name[1]; /* Alias name */ ++} cupsd_alias_t; ++ ++ ++/* + * Globals... + */ + +@@ -65,7 +76,12 @@ VAR char *ConfigurationFile VALUE(NULL) + /* Directory for request files */ + *DocumentRoot VALUE(NULL); + /* Root directory for documents */ +-VAR int ServerNameIsIP VALUE(0); ++VAR cups_array_t *ServerAlias VALUE(NULL); ++ /* Alias names for server */ ++VAR int RemoteAccessEnabled VALUE(0), ++ /* Are we listening on non-local addresses? */ ++ ServerNameIsIP VALUE(0); ++ /* Is the ServerName an IP address? */ + VAR int NumSystemGroups VALUE(0); + /* Number of system group names */ + VAR char *SystemGroups[MAX_SYSTEM_GROUPS] +--- a/scheduler/listen.c ++++ b/scheduler/listen.c +@@ -143,18 +143,6 @@ cupsdStartListening(void) + cupsArrayCount(Listeners)); + + /* +- * Get the server's IP address... +- */ +- +- if (ServerAddrs) +- httpAddrFreeList(ServerAddrs); +- +- if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL) +- cupsdLogMessage(CUPSD_LOG_ERROR, +- "Unable to find IP address for server name \"%s\"!\n", +- ServerName); +- +- /* + * Setup socket listeners... + */ + +--- a/scheduler/network.c ++++ b/scheduler/network.c +@@ -100,8 +100,8 @@ cupsdNetIFUpdate(void) + cupsd_netif_t *temp; /* New interface */ + struct ifaddrs *addrs, /* Interface address list */ + *addr; /* Current interface address */ +- http_addrlist_t *saddr; /* Current server address */ + char hostname[1024]; /* Hostname for address */ ++ size_t hostlen; /* Length of hostname */ + + + /* +@@ -155,7 +155,7 @@ cupsdNetIFUpdate(void) + * Try looking up the hostname for the address as needed... + */ + +- if (HostNameLookups) ++ if (HostNameLookups || RemoteAccessEnabled) + httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname, + sizeof(hostname)); + else +@@ -169,25 +169,16 @@ cupsdNetIFUpdate(void) + if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr))) + strcpy(hostname, "localhost"); + else +- { +- for (saddr = ServerAddrs; saddr; saddr = saddr->next) +- if (httpAddrEqual((http_addr_t *)(addr->ifa_addr), &(saddr->addr))) +- break; +- +- if (saddr) +- strlcpy(hostname, ServerName, sizeof(hostname)); +- else +- httpAddrString((http_addr_t *)(addr->ifa_addr), hostname, +- sizeof(hostname)); +- } ++ httpAddrString((http_addr_t *)(addr->ifa_addr), hostname, ++ sizeof(hostname)); + } + + /* + * Create a new address element... + */ + +- if ((temp = calloc(1, sizeof(cupsd_netif_t) + +- strlen(hostname))) == NULL) ++ hostlen = strlen(hostname); ++ if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL) + break; + + /* +@@ -195,6 +186,7 @@ cupsdNetIFUpdate(void) + */ + + strlcpy(temp->name, addr->ifa_name, sizeof(temp->name)); ++ temp->hostlen = hostlen; + strcpy(temp->hostname, hostname); /* Safe because hostname is allocated */ + + if (addr->ifa_addr->sa_family == AF_INET) +--- a/scheduler/network.h ++++ b/scheduler/network.h +@@ -25,6 +25,7 @@ typedef struct cupsd_netif_s /**** Netw + http_addr_t address, /* Network address */ + mask, /* Network mask */ + broadcast; /* Broadcast address */ ++ size_t hostlen; /* Length of hostname */ + char name[32], /* Network interface name */ + hostname[1]; /* Hostname associated with interface */ + } cupsd_netif_t;