--- /dev/null
+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...
+ */
--- /dev/null
+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;
+ }
+ }
+
--- /dev/null
+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...
+ */
--- /dev/null
+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? */
--- /dev/null
+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
--- /dev/null
+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);
+
--- /dev/null
+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);
--- /dev/null
+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 */
--- /dev/null
+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 <CODE>roo
+ HREF="#ServerName"><CODE>ServerName</CODE></A>.</P>
+
+
++<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.3.10</SPAN><A NAME="ServerAlias">ServerAlias</A></H2>
++
++<H3>Examples</H3>
++
++<PRE CLASS="command">
++ServerAlias althost
++ServerAlias althost.foo.com
++ServerAlias althost.bar.com
++ServerAlias *
++</PRE>
++
++<H3>Description</H3>
++
++<P>The <CODE>ServerAlias</CODE> directive specifies alternate names that the
++server is known by. By default it contains a list of all aliases associated
++with the <A HREF="#ServerName"><CODE>ServerName</CODE></A>. The special name
++"*" can be used to allow any hostname when accessing CUPS via an external
++network interfaces.</P>
++
++<BLOCKQUOTE><B>Note</B>
++
++<P>The <CODE>ServerAlias</CODE> 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 "*".</P>
++
++</BLOCKQUOTE>
++
++
+ <H2 CLASS="title"><A NAME="ServerBin">ServerBin</A></H2>
+
+ <H3>Examples</H3>
+--- 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;