Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CERT VU#810572: Privilege escalation through dynamic linker and isolated vulnerabilities #4609

Closed
michaelrsweet opened this issue Mar 23, 2015 · 33 comments
Milestone

Comments

@michaelrsweet
Copy link
Collaborator

Version: 2.0.2
CUPS.org User: mike

We received a report from Google that cupsd can be exploited to perform a privilege escalation using a combination of bugs and the dynamic linker's support for (pre)loading or redirecting which shared libraries are used by the cups-exec helper program.

The exact attack does the following:

  1. Use the CGI template engine to inject malicious HTML in a hyperlink, which is executed by the browser (a similar attack could be performed by a specially written program)
  2. A specially-crafted print-job or create-job request is sent to cupsd containing the job-originating-host-name attribute with multiple nameWithLanguage values - this triggers a validation error in cupsd, which then tries to free the language strings multiple times.
  3. The language string passed in is /admin, which causes the cupsd.conf ACL's copy of the string to become corrupted, allowing anyone to PUT a new cupsd.conf file.
  4. A new cupsd.conf file is uploaded to cupsd containing SetEnv directives (for DYLD_PRELOAD or LD_PRELOAD) pointing to a malicious dynamic library.
  5. The next job or request that triggers the execution of a helper program through cups-exec, and the dynamic linker loads the malicious code. Depending on the version of CUPS and platform, the code will execute either as the "lp" user or "root".

This attack can be done remotely when printer sharing and the web interface is enabled, using failed POST or PUT requests to collect stale request files in the CUPS spool directory containing the malicious code.

This bug tracks resolution of this privilege escalation issue through the following changes:

  • cupsd should use the ippSetCount and ippSetString APIs rather than manipulating the string values directly, particularly for the processing of the job-originating-host-name attribute.
  • cupsd shouldn't use string pool for config stuff
  • cupsd should remove temp files on partial POST/PUT
  • cupsd shouldn't support LD_* and DYLD_* variables when running as root
  • Need to call cgiClearVariables in more places to prevent input from leaking into output
  • Add new cgiSetVariable function to flag variables that are already encoded HTML, and only give them special treatment
@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

OK, the proposed fixes are attached. Holding bug in pending state until I commit to the public repo...

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: twaugh.redhat

Patch looks good to me. How about this sort of thing, in cgi-bin/admin.c? Shouldn't that be changed too?:

(line 767):
if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
{
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
num_printers, NULL, NULL);
for (i = 0; i < num_printers; i ++)
attr->values[i].string.text = _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i));
}

(line 2948):
/*
* Add the name...
*/

    attr->values[i].string.text = _cupsStrAlloc(ptr);

etc

In cups/encode.c:768 there's also this:
/*
* Copy the option value(s) over as needed by the type...
*/

  switch (attr->value_tag)
  {

[...]
default :
if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL)

and cups/ipp.c uses _cupsStrAlloc() for IPP strings all over the place still.

There's another instance in scheduler/job.c:5305:

/*

  • Copy the reasons...
    */

    for (i = 0; i < num_reasons; i ++)
    job->printer_reasons->values[i].string.text = _cupsStrAlloc(reasons[i]);

and several in scheduler/printers.c:
scheduler/printers.c:490: attr->values[0].string.text = _cupsStrAlloc("none");
scheduler/printers.c:1995: attr->values[i].string.text = _cupsStrAlloc(start);
scheduler/printers.c:2108: attr->values[i].string.text = _cupsStrAlloc(name);
scheduler/printers.c:2133: attr->values[0].string.text = _cupsStrAlloc(Classification ?
scheduler/printers.c:2135: attr->values[1].string.text = _cupsStrAlloc(Classification ?
scheduler/printers.c:2175: attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name);
scheduler/printers.c:2275: _cupsStrAlloc(oldattr->values[i].string.text);
scheduler/printers.c:2329: _cupsStrAlloc(oldattr->values[i].string.text);
scheduler/printers.c:2342: _cupsStrAlloc(oldattr->values[i].string.text);
scheduler/printers.c:3462: attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
scheduler/printers.c:3470: attr->values[i].string.text = _cupsStrAlloc(mimetype);
scheduler/printers.c:3923: val->string.text = _cupsStrAlloc(pwgsize->map.pwg);
scheduler/printers.c:3927: val->string.text = _cupsStrAlloc(p->pc->custom_min_keyword);
scheduler/printers.c:3929: val->string.text = _cupsStrAlloc(p->pc->custom_max_keyword);
scheduler/printers.c:3981: val->string.text = _cupsStrAlloc(pwgsource->pwg);
scheduler/printers.c:3997: val->string.text = _cupsStrAlloc(pwgtype->pwg);
scheduler/printers.c:4197: val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg);
scheduler/printers.c:4283: val->string.text = _cupsStrAlloc(mandatory);
scheduler/printers.c:4518: attr->values[count].string.text = _cupsStrAlloc(start);
scheduler/printers.c:4570: attr->values[0].string.text = _cupsStrAlloc("none");
scheduler/printers.c:4575: attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value);
scheduler/printers.c:4580: attr->values[i].string.text = _cupsStrAlloc("tbcp");
scheduler/printers.c:4582: attr->values[i].string.text = _cupsStrAlloc("bcp");

These three in systemv/lpadmin.c also look wrong:
systemv/lpadmin.c:786: _cupsStrAlloc(members->values[i].string.text);
systemv/lpadmin.c:788: attr->values[i].string.text = _cupsStrAlloc(uri);
systemv/lpadmin.c:1045: _cupsStrAlloc(members->values[j].string.text);

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

The IPP code still uses the global string pool - the only change was to make the config file strings (cupsdClear/SetString stuff) use strdup/free so they didn't share the same string pool.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: twaugh.redhat

Alright. Don't we want all of scheduler/*.c to be using ippSetString() rather than _cupsStrAlloc() directly when setting IPP strings, for the extra checking it provides?

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Eventually, yes, but for now I just wanted to focus on the uses that needed to be changed (from cupsdSetString to ippSetString).

The long-term goal is for cupsd to not depend on any private APIs.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: jsmeix.suse

As far as I understand the initial comment
items 1. + 2. result 3. which means:

An attacker from remote who is allowed to submit print jobs to
a CUPS server can upload a new cupsd.conf file onto that server.

Or do I misunderstand it and items 1. + 2. require that the
attacker can log in on the CUPS server?

Did Google provide a reproducer so that one could reproduce
the issue (in particular also on older CUPS versions)?

If I am right this is similar to
http:https://www.cups.org/str.php?L4223
but here it seems anyone who is allowed to submit print jobs
can replace cupsd.conf on the server.

When a remote attacker can upload a new config file for a service
that runs as root, he controls a process that runs as root (he may
have to wait until the service was restarted - e.g. for the cupsd)
which means everything is then lost so that it does not really matter
what specific way the attacker later uses to do further bad things.

In the end I like to separate items 1. + 2. => 3. from the rest
(provided my understanding is right.)

In this case here the further bad things are via DYLD_PRELOAD/LD_PRELOAD
to run arbitrary stuff usually as user 'lp' which seems that the attacker
must be able to log in on the CUPS server to place his evil library there.

But I wonder if the attacker could also upload his evil library as print
job data onto the CUPS server (via "lp -h cups.server -H hold my_library"
provided the CUPS server accepts biary data to be printed) and then
refer to that library on the CUPS server as /var/spool/cups/d...

If this is possible it would mean:

An attacker from remote who is allowed to submit print jobs to
a CUPS server can upload a new cupsd.conf file onto that server
plus a selfmade evil library as /var/spool/cups/d...

Regardless if "evil library upload" is also possible or not
I think the actual issue is item 1. and 2. in the initial comment
more specifically I think the root issue is that cupsd.conf can
be replaced from remote via PUT.

Therefore I wonder if we should perhaps gererally disable the
functionality to upload a new cupsd.conf file onto a CUPS server
(via HTTP PUT) regardless that this is a regression because
functionality that had worked becomes disabled?

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: jsmeix.suse

Correction of my last paragraph ("from remote" was missing):

I wonder if we should perhaps gererally disable
the functionality to upload a new cupsd.conf file
onto a CUPS server from_remote (via HTTP PUT).

Currently (for now only an untested idea) I am thinking about
to reject HTTP PUT requests if the client hostname is not "localhost".
This way cupsctl should still work when it is run directly
on the CUPS server and hopefully even editing cupsd.conf
via web interface when it is called as "http:https://localhost:631"
should still work but uploading cupsd.conf from remote
(e.g. via CUPS web interface or via any selfmade program)
would be rejected by the cupsd.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Johannes,

There are still valid reasons to allow configuration for remote updates (think managed server environments using things like puppet), and restricting to localhost would not help in this case anyways - the exploit can be done through a malicious link to localhost or a locally-run program or script.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Patch for CUPS 1.7

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Patch for CUPS 1.6

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Patch for CUPS 1.5

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Patch for CUPS 1.4

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Patch for CUPS 1.3

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Patch for CUPS 1.2

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Finally, the patch for CUPS 1.1.x which is much simpler since it doesn't have a string pool or the web interface vulnerability.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: twaugh.redhat

Are there CVE names for any of these vulnerabilities?

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Not yet; I've asked for Apple Security to take care of it but they need to coordinate with Google...

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: jsmeix.suse

In str4609-1.1.patch
https://www.cups.org/strfiles.php/3486/str4609-1.1.patch

the only actual change is in scheduler/ipp.c

  •         if (attr->values[i].string.charset)
    

+ if (!i && attr->values[i].string.charset)

in the create_job function therein at "Free old strings..."
when the request contains a job-originating-host-name attribute.

The same "Free old strings..." functionality exists also
in the print_job function but there it is left unchanged.

As far as I know, create_job and print_job can both be used
to submit a print job so that I wonder why it is not changed
in the same way also for the print_job function?

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Johannes,

You are right, I forgot to change print_job as well - that is all you need to add.

(keep in mind that that this will just crash cupsd in 1.1 - it is not possible to exploit 1.1.x in the same way as the newer versions of CUPS since it did not use the string pool...)

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Assigned CERT VU#810572.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: carnil

Hi

Do you know if a CVE has been assigned in meanwhile to reference this issue?

Regards,

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

No CVE, just the VU#.

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: mike

Fixed in Subversion repository.

@michaelrsweet
Copy link
Collaborator Author

"str4609.patch":

Index: cgi-bin/ipp-var.c

--- cgi-bin/ipp-var.c (revision 12557)
+++ cgi-bin/ipp-var.c (working copy)
@@ -3,7 +3,7 @@
*

  • CGI <-> IPP variable routines for CUPS.
    *
    • * Copyright 2007-2014 by Apple Inc.
    • * Copyright 2007-2015 by Apple Inc.
  • Copyright 1997-2007 by Easy Software Products.
    *
  • These coded instructions, statements, and computer programs are the
    @@ -1202,21 +1202,7 @@
    * Rewrite URIs...
    */
  •          if (!strcmp(name, "member_uris"))
    
  •     {
    

- char url[1024]; /* URL for class member... */

  •   cgiRewriteURL(attr->values[i].string.text, url,
    

- sizeof(url), NULL);

  •            snprintf(valptr, sizeof(value) - (size_t)(valptr - value),
    
  •            "<A HREF=\"%s\">%s</A>", url,
    
  •        strrchr(attr->values[i].string.text, '/') + 1);
    
  •     }
    
  •     else
    
  •   cgiRewriteURL(attr->values[i].string.text, valptr,
    
  •                 (int)(sizeof(value) - (size_t)(valptr - value)), NULL);
    
  •     cgiRewriteURL(attr->values[i].string.text, valptr, (int)(sizeof(value) - (size_t)(valptr - value)), NULL);
           break;
         }
    

Index: cgi-bin/template.c

--- cgi-bin/template.c (revision 12557)
+++ cgi-bin/template.c (working copy)
@@ -3,7 +3,7 @@
*

  • CGI template function.
    *

    • * Copyright 2007-2014 by Apple Inc.
    • * Copyright 2007-2015 by Apple Inc.
  • Copyright 1997-2006 by Easy Software Products.
    *

  • These coded instructions, statements, and computer programs are the
    @@ -648,39 +648,7 @@
    while (_s)
    {
    if (_s == '<')

    • {
    • /*
      
    •  \* Pass <A HREF="url"> and </A>, otherwise quote it...
      

    - */

    •  if (!_cups_strncasecmp(s, "<A HREF=\"", 9))
      
    •  {
      
    •    fputs("<A HREF=\"", out);
      

    - s += 9;

    • while (*s && *s != '"')
    • {
    •      if (*s == '&')
      
    •        fputs("&amp;", out);
      
    • else
      

    - putc(*s, out);

    • s ++;
      

    - }

    •    if (*s)
      

    - s ++;

    • fputs("">", out);
    •  }
      
    •  else if (!_cups_strncasecmp(s, "</A>", 4))
      
    •  {
      
    •    fputs("</A>", out);
      
    • s += 3;
    •  }
      
    •  else
      
    •    fputs("&lt;", out);
      
    • }
    •  fputs("&lt;", out);
      

      else if (_s == '>')
      fputs(">", out);
      else if (_s == '"')
      Index: scheduler/client.c

      --- scheduler/client.c (revision 12557)
      +++ scheduler/client.c (working copy)
      @@ -3,7 +3,7 @@
      *
  • Client routines for the CUPS scheduler.
    *

    • * Copyright 2007-2014 by Apple Inc.
    • * Copyright 2007-2015 by Apple Inc.
  • Copyright 1997-2007 by Easy Software Products, all rights reserved.
    *

  • This file contains Kerberos support code, copyright 2006 by
    @@ -484,7 +484,12 @@

    httpClose(con->http);

  • cupsdClearString(&con->filename);

  • if (con->filename)

  • {

  •  unlink(con->filename);
    
  •  cupsdClearString(&con->filename);
    
  • }

cupsdClearString(&con->command);
cupsdClearString(&con->options);
cupsdClearString(&con->query_string);

Index: scheduler/conf.c

--- scheduler/conf.c (revision 12557)
+++ scheduler/conf.c (working copy)
@@ -407,7 +407,7 @@

  • to use it...
    */
  • if (gss_init_sec_context == NULL)
  • if (&gss_init_sec_context == NULL)
    return (default_auth_type = CUPSD_AUTH_BASIC);

endif /* APPLE */

Index: scheduler/env.c

--- scheduler/env.c (revision 12557)
+++ scheduler/env.c (working copy)
@@ -1,27 +1,16 @@
/*

  • "$Id$"
    *

    • * Environment management routines for the CUPS scheduler.
    • * Environment management routines for the CUPS scheduler.
      *
    • * Copyright 2007-2011 by Apple Inc.
    • * Copyright 1997-2006 by Easy Software Products, all rights reserved.
    • * Copyright 2007-2014 by Apple Inc.
    • * Copyright 1997-2006 by Easy Software Products, all rights reserved.
      *
    • * These coded instructions, statements, and computer programs are the
    • * property of Apple Inc. and are protected by Federal copyright
    • * law. Distribution and use rights are outlined in the file "LICENSE.txt"
    • * which should have been included with this file. If this file is
    • * file is missing or damaged, see the license at "http:https://www.cups.org/".
    • * Contents:
    • * cupsdInitEnv() - Initialize the current environment with standard
    • * variables.
    • * cupsdLoadEnv() - Copy common environment variables into an array.
    • * cupsdSetEnv() - Set a common environment variable.
    • * cupsdSetEnvf() - Set a formatted common environment variable.
    • * cupsdUpdateEnv() - Update the environment for the configured directories.
    • * clear_env() - Clear common environment variables.
    • * find_env() - Find a common environment variable.
    • * These coded instructions, statements, and computer programs are the
    • * property of Apple Inc. and are protected by Federal copyright
    • * law. Distribution and use rights are outlined in the file "LICENSE.txt"
    • * which should have been included with this file. If this file is
    • * file is missing or damaged, see the license at "http:https://www.cups.org/".
      */

    /*
    @@ -131,6 +120,13 @@
    return;

    /*

    • * Do not allow dynamic linker variables when running as root...
    • */
    • if (!RunUser && (!strncmp(name, "DYLD_", 5) || !strncmp(name, "LD_", 3)))
    • return;
    • /*
    • See if this variable has already been defined...
      */

Index: scheduler/ipp.c

--- scheduler/ipp.c (revision 12557)
+++ scheduler/ipp.c (working copy)
@@ -3,7 +3,7 @@
*

  • IPP routines for the CUPS scheduler.
    *
    • * Copyright 2007-2014 by Apple Inc.
    • * Copyright 2007-2015 by Apple Inc.
  • Copyright 1997-2007 by Easy Software Products, all rights reserved.
    *
  • This file contains Kerberos support code, copyright 2006 by
    @@ -409,8 +409,7 @@
    * Remote unauthenticated user masquerading as local root...
    */
  •   _cupsStrFree(username->values[0].string.text);
    
  •   username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    
  •        ippSetString(con->request, &username, 0, RemoteRoot);
    
    }
    }

@@ -1556,7 +1555,7 @@
cupsdSetString(&job->username, con->username);

 if (attr)
  •  cupsdSetString(&attr->values[0].string.text, con->username);
    
  •  ippSetString(job->attrs, &attr, 0, con->username);
    
    }
    else if (attr)
    {
    @@ -1574,9 +1573,8 @@
    "job-originating-user-name", NULL, job->username);
    else
    {
  • attr->group_tag = IPP_TAG_JOB;
  • _cupsStrFree(attr->name);
  • attr->name = _cupsStrAlloc("job-originating-user-name");
  • ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
  • ippSetName(job->attrs, &attr, "job-originating-user-name");
    }

if (con->username[0] || auth_info)
@@ -1610,48 +1608,11 @@

  • Also, we can only have 1 value and it must be a name value.
    */
  •  switch (attr->value_tag)
    
  •  {
    
  •    case IPP_TAG_STRING :
    
  • case IPP_TAG_TEXTLANG :
  • case IPP_TAG_NAMELANG :
  • case IPP_TAG_TEXT :
  • case IPP_TAG_NAME :
  • case IPP_TAG_KEYWORD :
  • case IPP_TAG_URI :
  • case IPP_TAG_URISCHEME :
  • case IPP_TAG_CHARSET :
  • case IPP_TAG_LANGUAGE :
  • case IPP_TAG_MIMETYPE :
  •  /*
    
  •   \* Free old strings...
    

- */

  •   for (i = 0; i < attr->num_values; i ++)
    
  •   {
    
  •     _cupsStrFree(attr->values[i].string.text);
    
  •     attr->values[i].string.text = NULL;
    
  •     if (attr->values[i].string.language)
    
  •     {
    
  •   _cupsStrFree(attr->values[i].string.language);
    
  •   attr->values[i].string.language = NULL;
    
  •     }
    

- }

  • default :
  •        break;
    

- }

  • /*
    
  •  \* Use the default connection hostname instead...
    

- */

  •  attr->value_tag             = IPP_TAG_NAME;
    
  •  attr->num_values            = 1;
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->http->hostname);
    
  •  ippDeleteAttribute(job->attrs, attr);
    
  •  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http->hostname);
    

    }

  • attr->group_tag = IPP_TAG_JOB;

  • else

  •  ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
    

    }
    else
    {
    @@ -1747,8 +1708,8 @@

    attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
    2, NULL, NULL);

  •  attr->values[0].string.text = _cupsStrRetain(printer->job_sheets[0]);
    
  •  attr->values[1].string.text = _cupsStrRetain(printer->job_sheets[1]);
    
  •  ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]);
    
  •  ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]);
    

    }

    job->job_sheets = attr;
    @@ -1774,7 +1735,7 @@
    * Force the leading banner to have the classification on it...
    */

  •      cupsdSetString(&attr->values[0].string.text, Classification);
    
  •      ippSetString(job->attrs, &attr, 0, Classification);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,none", "
    @@ -1791,7 +1752,7 @@

    • Can't put two different security markings on the same document!
      */
  •      cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
    
  •      ippSetString(job->attrs, &attr, 1, attr->values[0].string.text);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,%s", "
    @@ -1831,18 +1792,18 @@
    if (attr->num_values > 1 &&
    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
    {

  •      cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •      cupsdSetString(&(attr->values[1].string.text), Classification);
    
  •      ippSetString(job->attrs, &attr, 0, Classification);
    
  •      ippSetString(job->attrs, &attr, 1, Classification);
    

    }
    else
    {
    if (attr->num_values == 1 ||
    strcmp(attr->values[0].string.text, "none"))

  •        cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •        ippSetString(job->attrs, &attr, 0, Classification);
    
       if (attr->num_values > 1 &&
      strcmp(attr->values[1].string.text, "none"))
    
  •        cupsdSetString(&(attr->values[1].string.text), Classification);
    
  •   ippSetString(job->attrs, &attr, 1, Classification);
     }
    
     if (attr->num_values > 1)
    

    @@ -3069,8 +3030,8 @@

    if (attr)
    {

  • attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");

  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);

  • ippSetString(job->attrs, &attr, 0, "no-hold");
    }

/*
@@ -8191,11 +8152,7 @@
filetype->type);

if (format)

  • {

- _cupsStrFree(format->values[0].string.text);

  •  format->values[0].string.text = _cupsStrAlloc(mimetype);
    
  • }

  •  ippSetString(con->request, &format, 0, mimetype);
    

    else
    ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
    "document-format", NULL, mimetype);
    @@ -8732,11 +8689,9 @@

    if (attr)
    {

  • _cupsStrFree(attr->values[0].string.text);

  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);

  • ippSetString(job->attrs, &attr, 0, "no-hold");

  • attr->value_tag = IPP_TAG_KEYWORD;

- attr->values[0].string.text = _cupsStrAlloc("no-hold");

 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
               "Job job-hold-until value changed by user.");
 ippSetString(job->attrs, &job->reasons, 0, "none");

@@ -9425,11 +9380,7 @@

 if ((jformat = ippFindAttribute(job->attrs, "document-format",
                                 IPP_TAG_MIMETYPE)) != NULL)
  • {

- _cupsStrFree(jformat->values[0].string.text);

  •  jformat->values[0].string.text = _cupsStrAlloc(mimetype);
    
  • }

  •  ippSetString(job->attrs, &jformat, 0, mimetype);
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
    "document-format", NULL, mimetype);

    Index: scheduler/job.c

    --- scheduler/job.c (revision 12557)
    +++ scheduler/job.c (working copy)
    @@ -377,7 +377,7 @@

       if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
                               IPP_TAG_URI)) != NULL)
    
  •        cupsdSetString(&attr->values[0].string.text, printer->uri);
    
  •        ippSetString(job->attrs, &attr, 0, printer->uri);
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
    "job-actual-printer-uri", NULL, printer->uri);
    @@ -2096,7 +2096,7 @@

    if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
    IPP_TAG_URI)) != NULL)

  • cupsdSetString(&(attr->values[0].string.text), p->uri);

  • ippSetString(job->attrs, &attr, 0, p->uri);

cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
"Job #%d moved from %s to %s.", job->id, olddest,
@@ -2293,7 +2293,7 @@
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);

if (attr)

  •  cupsdSetString(&(attr->values[0].string.text), when);
    
  •  ippSetString(job->attrs, &attr, 0, when);
    

    else
    attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
    "job-hold-until", NULL, when);
    @@ -2548,8 +2548,8 @@

    if (attr)
    {

  • attr->value_tag = IPP_TAG_KEYWORD;
    
  • cupsdSetString(&(attr->values[0].string.text), "no-hold");
    
  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);
    
  • ippSetString(job->attrs, &attr, 0, "no-hold");
    

    }

    default :
    @@ -4595,7 +4595,7 @@
    "job-printer-state-message",
    IPP_TAG_TEXT);
    if (job->printer_message)

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");

  • ippSetString(job->attrs, &job->printer_message, 0, "");

ippSetString(job->attrs, &job->reasons, 0, "job-printing");
cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL);
@@ -5235,15 +5235,14 @@
if (job->state_value != IPP_JOB_PROCESSING &&
job->status_level == CUPSD_LOG_INFO)
{

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");
  • ippSetString(job->attrs, &job->printer_message, 0, "");

job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
else if (job->printer->state_message[0] && do_message)
{

  • cupsdSetString(&(job->printer_message->values[0].string.text),
  •      job->printer->state_message);
    
  • ippSetString(job->attrs, &job->printer_message, 0, job->printer->state_message);

job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);

Index: scheduler/main.c

--- scheduler/main.c (revision 12557)
+++ scheduler/main.c (working copy)
@@ -3,7 +3,7 @@
*

  • Main loop for the CUPS scheduler.
    *

  • * Copyright 2007-2014 by Apple Inc.

  • * Copyright 2007-2015 by Apple Inc.

    • Copyright 1997-2007 by Easy Software Products, all rights reserved.
      *
    • These coded instructions, statements, and computer programs are the
      @@ -1137,8 +1137,8 @@
      if (!*a)
      *a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
      (cups_ahash_func_t)NULL, 0,
  •          (cups_acopy_func_t)_cupsStrAlloc,
    
  •          (cups_afree_func_t)_cupsStrFree);
    
  •          (cups_acopy_func_t)strdup,
    
  •          (cups_afree_func_t)free);
    

    return (cupsArrayAdd(*a, (char *)s));
    }
    @@ -1168,7 +1168,7 @@
    {
    if (s && *s)
    {

  • _cupsStrFree(*s);

  • free(*s);
    *s = NULL;
    }
    }
    @@ -1249,10 +1249,10 @@
    return;

if (*s)

  • _cupsStrFree(*s);
  • free(*s);

if (v)

  • *s = _cupsStrAlloc(v);
  • *s = strdup(v);
    else
    *s = NULL;
    }
    @@ -1283,13 +1283,13 @@
    vsnprintf(v, sizeof(v), f, ap);
    va_end(ap);
  • *s = _cupsStrAlloc(v);
  • *s = strdup(v);
    }
    else
    *s = NULL;

if (olds)

  • _cupsStrFree(olds);
  • free(olds);
    }

@@ -1449,8 +1449,7 @@
}

    if (job->printer_message)
  •     cupsdSetString(&(job->printer_message->values[0].string.text),
    
  •            message);
    
  •     ippSetString(job->attrs, &job->printer_message, 0, message);
    
    }
    }

@michaelrsweet
Copy link
Collaborator Author

"str4609-1.7.patch":

Index: cgi-bin/template.c

--- cgi-bin/template.c (revision 12548)
+++ cgi-bin/template.c (revision 12588)
@@ -659,39 +659,7 @@
while (_s)
{
if (_s == '<')

  • {
  • /*
    
  •  \* Pass <A HREF="url"> and </A>, otherwise quote it...
    

- */

  •  if (!_cups_strncasecmp(s, "<A HREF=\"", 9))
    
  •  {
    
  •    fputs("<A HREF=\"", out);
    

- s += 9;

  • while (*s && *s != '"')
  • {
  •      if (*s == '&')
    
  •        fputs("&amp;", out);
    
  • else
    

- putc(*s, out);

  • s ++;
    

- }

  •    if (*s)
    

- s ++;

  • fputs("">", out);

  •  }
    
  •  else if (!_cups_strncasecmp(s, "</A>", 4))
    
  •  {
    
  •    fputs("</A>", out);
    
  • s += 3;

  •  }
    
  •  else
    
  •    fputs("&lt;", out);
    
  • }

  •  fputs("&lt;", out);
    

    else if (_s == '>')
    fputs(">", out);
    else if (_s == '"')

    Index: cgi-bin/ipp-var.c

    --- cgi-bin/ipp-var.c (revision 12548)
    +++ cgi-bin/ipp-var.c (revision 12588)
    @@ -1230,21 +1230,7 @@
    * Rewrite URIs...
    */

  •          if (!strcmp(name, "member_uris"))
    
  •     {
    

- char url[1024]; /* URL for class member... */

  •   cgiRewriteURL(attr->values[i].string.text, url,
    

- sizeof(url), NULL);

  •            snprintf(valptr, sizeof(value) - (valptr - value),
    
  •            "<A HREF=\"%s\">%s</A>", url,
    
  •        strrchr(attr->values[i].string.text, '/') + 1);
    
  •     }
    
  •     else
    
  •   cgiRewriteURL(attr->values[i].string.text, valptr,
    
  •                 sizeof(value) - (valptr - value), NULL);
    
  •     cgiRewriteURL(attr->values[i].string.text, valptr, sizeof(value) - (valptr - value), NULL);
           break;
         }
    

Index: scheduler/ipp.c

--- scheduler/ipp.c (revision 12548)
+++ scheduler/ipp.c (revision 12588)
@@ -3,7 +3,7 @@
*

  • IPP routines for the CUPS scheduler.
    *
    • * Copyright 2007-2014 by Apple Inc.
    • * Copyright 2007-2015 by Apple Inc.
  • Copyright 1997-2007 by Easy Software Products, all rights reserved.
    *
  • This file contains Kerberos support code, copyright 2006 by
    @@ -412,8 +412,7 @@
    * Remote unauthenticated user masquerading as local root...
    */
  •   _cupsStrFree(username->values[0].string.text);
    
  •   username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    
  •        ippSetString(con->request, &username, 0, RemoteRoot);
    
    }
    }

@@ -1577,7 +1576,7 @@
cupsdSetString(&job->username, con->username);

 if (attr)
  •  cupsdSetString(&attr->values[0].string.text, con->username);
    
  •  ippSetString(job->attrs, &attr, 0, con->username);
    
    }
    else if (attr)
    {
    @@ -1595,9 +1594,8 @@
    "job-originating-user-name", NULL, job->username);
    else
    {
  • attr->group_tag = IPP_TAG_JOB;
  • _cupsStrFree(attr->name);
  • attr->name = _cupsStrAlloc("job-originating-user-name");
  • ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
  • ippSetName(job->attrs, &attr, "job-originating-user-name");
    }

if (con->username[0] || auth_info)
@@ -1628,48 +1626,11 @@

  • Also, we can only have 1 value and it must be a name value.
    */
  •  switch (attr->value_tag)
    
  •  {
    
  •    case IPP_TAG_STRING :
    
  • case IPP_TAG_TEXTLANG :
  • case IPP_TAG_NAMELANG :
  • case IPP_TAG_TEXT :
  • case IPP_TAG_NAME :
  • case IPP_TAG_KEYWORD :
  • case IPP_TAG_URI :
  • case IPP_TAG_URISCHEME :
  • case IPP_TAG_CHARSET :
  • case IPP_TAG_LANGUAGE :
  • case IPP_TAG_MIMETYPE :
  •  /*
    
  •   \* Free old strings...
    

- */

  •   for (i = 0; i < attr->num_values; i ++)
    
  •   {
    
  •     _cupsStrFree(attr->values[i].string.text);
    
  •     attr->values[i].string.text = NULL;
    
  •     if (attr->values[i].string.language)
    
  •     {
    
  •   _cupsStrFree(attr->values[i].string.language);
    
  •   attr->values[i].string.language = NULL;
    
  •     }
    

- }

  • default :
  •        break;
    

- }

  • /*
    
  •  \* Use the default connection hostname instead...
    

- */

  •  attr->value_tag             = IPP_TAG_NAME;
    
  •  attr->num_values            = 1;
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->http.hostname);
    
  •  ippDeleteAttribute(job->attrs, attr);
    
  •  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http.hostname);
    

    }

  • attr->group_tag = IPP_TAG_JOB;

  • else

  •  ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
    

    }
    else
    {
    @@ -1766,8 +1727,8 @@

    attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
    2, NULL, NULL);

  •  attr->values[0].string.text = _cupsStrRetain(printer->job_sheets[0]);
    
  •  attr->values[1].string.text = _cupsStrRetain(printer->job_sheets[1]);
    
  •  ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]);
    
  •  ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]);
    

    }

    job->job_sheets = attr;
    @@ -1793,7 +1754,7 @@
    * Force the leading banner to have the classification on it...
    */

  •      cupsdSetString(&attr->values[0].string.text, Classification);
    
  •      ippSetString(job->attrs, &attr, 0, Classification);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,none", "
    @@ -1810,7 +1771,7 @@

    • Can't put two different security markings on the same document!
      */
  •      cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
    
  •      ippSetString(job->attrs, &attr, 1, attr->values[0].string.text);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,%s", "
    @@ -1850,18 +1811,18 @@
    if (attr->num_values > 1 &&
    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
    {

  •      cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •      cupsdSetString(&(attr->values[1].string.text), Classification);
    
  •      ippSetString(job->attrs, &attr, 0, Classification);
    
  •      ippSetString(job->attrs, &attr, 1, Classification);
    

    }
    else
    {
    if (attr->num_values == 1 ||
    strcmp(attr->values[0].string.text, "none"))

  •        cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •        ippSetString(job->attrs, &attr, 0, Classification);
    
       if (attr->num_values > 1 &&
      strcmp(attr->values[1].string.text, "none"))
    
  •        cupsdSetString(&(attr->values[1].string.text), Classification);
    
  •   ippSetString(job->attrs, &attr, 1, Classification);
     }
    
     if (attr->num_values > 1)
    

    @@ -3089,8 +3050,8 @@

    if (attr)
    {

  • attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");

  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);

  • ippSetString(job->attrs, &attr, 0, "no-hold");
    }

/*
@@ -8105,11 +8066,7 @@
filetype->type);

if (format)

  • {

- _cupsStrFree(format->values[0].string.text);

  •  format->values[0].string.text = _cupsStrAlloc(mimetype);
    
  • }

  •  ippSetString(con->request, &format, 0, mimetype);
    

    else
    ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
    "document-format", NULL, mimetype);
    @@ -8645,11 +8602,9 @@

    if (attr)
    {

  • _cupsStrFree(attr->values[0].string.text);

  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);

  • ippSetString(job->attrs, &attr, 0, "no-hold");

  • attr->value_tag = IPP_TAG_KEYWORD;

- attr->values[0].string.text = _cupsStrAlloc("no-hold");

 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
               "Job job-hold-until value changed by user.");
 ippSetString(job->attrs, &job->reasons, 0, "none");

@@ -9341,11 +9296,7 @@

 if ((jformat = ippFindAttribute(job->attrs, "document-format",
                                 IPP_TAG_MIMETYPE)) != NULL)
  • {

- _cupsStrFree(jformat->values[0].string.text);

  •  jformat->values[0].string.text = _cupsStrAlloc(mimetype);
    
  • }

  •  ippSetString(job->attrs, &jformat, 0, mimetype);
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
    "document-format", NULL, mimetype);

    Index: scheduler/job.c

    --- scheduler/job.c (revision 12548)
    +++ scheduler/job.c (revision 12588)
    @@ -374,7 +374,7 @@

       if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
                               IPP_TAG_URI)) != NULL)
    
  •        cupsdSetString(&attr->values[0].string.text, printer->uri);
    
  •        ippSetString(job->attrs, &attr, 0, printer->uri);
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
    "job-actual-printer-uri", NULL, printer->uri);
    @@ -2008,7 +2008,7 @@

    if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
    IPP_TAG_URI)) != NULL)

  • cupsdSetString(&(attr->values[0].string.text), p->uri);

  • ippSetString(job->attrs, &attr, 0, p->uri);

cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
"Job #%d moved from %s to %s.", job->id, olddest,
@@ -2198,7 +2198,7 @@
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);

if (attr)

  •  cupsdSetString(&(attr->values[0].string.text), when);
    
  •  ippSetString(job->attrs, &attr, 0, when);
    

    else
    attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
    "job-hold-until", NULL, when);
    @@ -2452,8 +2452,8 @@

    if (attr)
    {

  • attr->value_tag = IPP_TAG_KEYWORD;
    
  • cupsdSetString(&(attr->values[0].string.text), "no-hold");
    
  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);
    
  • ippSetString(job->attrs, &attr, 0, "no-hold");
    

    }

    default :
    @@ -4442,7 +4442,7 @@
    "job-printer-state-message",
    IPP_TAG_TEXT);
    if (job->printer_message)

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");

  • ippSetString(job->attrs, &job->printer_message, 0, "");

ippSetString(job->attrs, &job->reasons, 0, "job-printing");
cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL);
@@ -5060,15 +5060,14 @@
if (job->state_value != IPP_JOB_PROCESSING &&
job->status_level == CUPSD_LOG_INFO)
{

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");
  • ippSetString(job->attrs, &job->printer_message, 0, "");

job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
else if (job->printer->state_message[0] && do_message)
{

  • cupsdSetString(&(job->printer_message->values[0].string.text),
  •      job->printer->state_message);
    
  • ippSetString(job->attrs, &job->printer_message, 0, job->printer->state_message);

job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);

Index: scheduler/client.c

--- scheduler/client.c (revision 12548)
+++ scheduler/client.c (revision 12588)
@@ -3,7 +3,7 @@
*

  • Client routines for the CUPS scheduler.
    *
  • * Copyright 2007-2014 by Apple Inc.
    • Copyright 2007-2015 by Apple Inc.
    • Copyright 1997-2007 by Easy Software Products, all rights reserved.
      *
    • This file contains Kerberos support code, copyright 2006 by
      @@ -598,7 +598,12 @@
      httpClearCookie(HTTP(con));
      httpClearFields(HTTP(con));
  • cupsdClearString(&con->filename);
  • if (con->filename)
  • {
  •  unlink(con->filename);
    
  •  cupsdClearString(&con->filename);
    
  • }

cupsdClearString(&con->command);
cupsdClearString(&con->options);
cupsdClearString(&con->query_string);
Index: scheduler/env.c

--- scheduler/env.c (revision 12548)
+++ scheduler/env.c (revision 12588)
@@ -1,27 +1,16 @@
/*

  • "$Id$"
    *

  • * Environment management routines for the CUPS scheduler.

  • * Environment management routines for the CUPS scheduler.
    *

  • * Copyright 2007-2011 by Apple Inc.

  • * Copyright 1997-2006 by Easy Software Products, all rights reserved.

  • * Copyright 2007-2014 by Apple Inc.

  • * Copyright 1997-2006 by Easy Software Products, all rights reserved.
    *

  • * These coded instructions, statements, and computer programs are the

  • * property of Apple Inc. and are protected by Federal copyright

  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"

  • * which should have been included with this file. If this file is

  • * file is missing or damaged, see the license at "http:https://www.cups.org/".

  • * Contents:

  • * cupsdInitEnv() - Initialize the current environment with standard

  • * variables.

  • * cupsdLoadEnv() - Copy common environment variables into an array.

  • * cupsdSetEnv() - Set a common environment variable.

  • * cupsdSetEnvf() - Set a formatted common environment variable.

  • * cupsdUpdateEnv() - Update the environment for the configured directories.

  • * clear_env() - Clear common environment variables.

  • * find_env() - Find a common environment variable.

  • * These coded instructions, statements, and computer programs are the

  • * property of Apple Inc. and are protected by Federal copyright

  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"

  • * which should have been included with this file. If this file is

  • /*
    @@ -131,6 +120,13 @@
    return;

    /*

  • * Do not allow dynamic linker variables when running as root...

  • */

  • if (!RunUser && (!strncmp(name, "DYLD_", 5) || !strncmp(name, "LD_", 3)))
  • return;
  • /*
    • See if this variable has already been defined...
      */

Index: scheduler/main.c

--- scheduler/main.c (revision 12548)
+++ scheduler/main.c (revision 12588)
@@ -3,7 +3,7 @@
*

  • Main loop for the CUPS scheduler.
    *

    • * Copyright 2007-2014 by Apple Inc.
    • * Copyright 2007-2015 by Apple Inc.
  • Copyright 1997-2007 by Easy Software Products, all rights reserved.
    *

  • These coded instructions, statements, and computer programs are the
    @@ -1144,8 +1144,8 @@
    if (!*a)
    *a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
    (cups_ahash_func_t)NULL, 0,

    •          (cups_acopy_func_t)_cupsStrAlloc,
      
    •          (cups_afree_func_t)_cupsStrFree);
      
    •          (cups_acopy_func_t)strdup,
      
    •          (cups_afree_func_t)free);
      

    return (cupsArrayAdd(*a, (char *)s));
    }
    @@ -1175,7 +1175,7 @@
    {
    if (s && *s)
    {

    • _cupsStrFree(*s);
    • free(*s);
      *s = NULL;
      }
      }
      @@ -1256,10 +1256,10 @@
      return;

    if (*s)

    • _cupsStrFree(*s);
    • free(*s);

    if (v)

    • *s = _cupsStrAlloc(v);
    • *s = strdup(v);
      else
      *s = NULL;
      }
      @@ -1290,13 +1290,13 @@
      vsnprintf(v, sizeof(v), f, ap);
      va_end(ap);
  • *s = _cupsStrAlloc(v);

  • *s = strdup(v);
    }
    else
    *s = NULL;

if (olds)

  • _cupsStrFree(olds);
  • free(olds);
    }

@@ -1647,8 +1647,7 @@
}

    if (job->printer_message)
  •     cupsdSetString(&(job->printer_message->values[0].string.text),
    
  •            message);
    
  •     ippSetString(job->attrs, &job->printer_message, 0, message);
    
    }
    }

@michaelrsweet
Copy link
Collaborator Author

"str4609-1.6.patch":

Index: cgi-bin/template.c

--- cgi-bin/template.c (revision 12550)
+++ cgi-bin/template.c (revision 12588)
@@ -659,39 +659,7 @@
while (_s)
{
if (_s == '<')

  • {
  • /*
    
  •  \* Pass <A HREF="url"> and </A>, otherwise quote it...
    

- */

  •  if (!_cups_strncasecmp(s, "<A HREF=\"", 9))
    
  •  {
    
  •    fputs("<A HREF=\"", out);
    

- s += 9;

  • while (*s && *s != '"')
  • {
  •      if (*s == '&')
    
  •        fputs("&amp;", out);
    
  • else
    

- putc(*s, out);

  • s ++;
    

- }

  •    if (*s)
    

- s ++;

  • fputs("">", out);

  •  }
    
  •  else if (!_cups_strncasecmp(s, "</A>", 4))
    
  •  {
    
  •    fputs("</A>", out);
    
  • s += 3;

  •  }
    
  •  else
    
  •    fputs("&lt;", out);
    
  • }

  •  fputs("&lt;", out);
    

    else if (_s == '>')
    fputs(">", out);
    else if (_s == '"')

    Index: cgi-bin/ipp-var.c

    --- cgi-bin/ipp-var.c (revision 12550)
    +++ cgi-bin/ipp-var.c (revision 12588)
    @@ -1230,21 +1230,7 @@
    * Rewrite URIs...
    */

  •          if (!strcmp(name, "member_uris"))
    
  •     {
    

- char url[1024]; /* URL for class member... */

  •   cgiRewriteURL(attr->values[i].string.text, url,
    

- sizeof(url), NULL);

  •            snprintf(valptr, sizeof(value) - (valptr - value),
    
  •            "<A HREF=\"%s\">%s</A>", url,
    
  •        strrchr(attr->values[i].string.text, '/') + 1);
    
  •     }
    
  •     else
    
  •   cgiRewriteURL(attr->values[i].string.text, valptr,
    
  •                 sizeof(value) - (valptr - value), NULL);
    
  •     cgiRewriteURL(attr->values[i].string.text, valptr, sizeof(value) - (valptr - value), NULL);
           break;
         }
    

Index: scheduler/ipp.c

--- scheduler/ipp.c (revision 12550)
+++ scheduler/ipp.c (revision 12588)
@@ -482,8 +482,7 @@
* Remote unauthenticated user masquerading as local root...
*/

  •   _cupsStrFree(username->values[0].string.text);
    
  •   username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    
  •        ippSetString(con->request, &username, 0, RemoteRoot);
    
    }
    }

@@ -1665,7 +1664,7 @@
cupsdSetString(&job->username, con->username);

 if (attr)
  •  cupsdSetString(&attr->values[0].string.text, con->username);
    
  •  ippSetString(job->attrs, &attr, 0, con->username);
    
    }
    else if (attr)
    {
    @@ -1683,9 +1682,8 @@
    "job-originating-user-name", NULL, job->username);
    else
    {
  • attr->group_tag = IPP_TAG_JOB;
  • _cupsStrFree(attr->name);
  • attr->name = _cupsStrAlloc("job-originating-user-name");
  • ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
  • ippSetName(job->attrs, &attr, "job-originating-user-name");
    }

if (con->username[0] || auth_info)
@@ -1716,48 +1714,11 @@

  • Also, we can only have 1 value and it must be a name value.
    */
  •  switch (attr->value_tag)
    
  •  {
    
  •    case IPP_TAG_STRING :
    
  • case IPP_TAG_TEXTLANG :
  • case IPP_TAG_NAMELANG :
  • case IPP_TAG_TEXT :
  • case IPP_TAG_NAME :
  • case IPP_TAG_KEYWORD :
  • case IPP_TAG_URI :
  • case IPP_TAG_URISCHEME :
  • case IPP_TAG_CHARSET :
  • case IPP_TAG_LANGUAGE :
  • case IPP_TAG_MIMETYPE :
  •  /*
    
  •   \* Free old strings...
    

- */

  •   for (i = 0; i < attr->num_values; i ++)
    
  •   {
    
  •     _cupsStrFree(attr->values[i].string.text);
    
  •     attr->values[i].string.text = NULL;
    
  •     if (attr->values[i].string.language)
    
  •     {
    
  •   _cupsStrFree(attr->values[i].string.language);
    
  •   attr->values[i].string.language = NULL;
    
  •     }
    

- }

  • default :
  •        break;
    

- }

  • /*
    
  •  \* Use the default connection hostname instead...
    

- */

  •  attr->value_tag             = IPP_TAG_NAME;
    
  •  attr->num_values            = 1;
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->http.hostname);
    
  •  ippDeleteAttribute(job->attrs, attr);
    
  •  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http.hostname);
    

    }

  • attr->group_tag = IPP_TAG_JOB;

  • else

  •  ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
    

    }
    else
    {
    @@ -1854,8 +1815,8 @@

    attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
    2, NULL, NULL);

  •  attr->values[0].string.text = _cupsStrRetain(printer->job_sheets[0]);
    
  •  attr->values[1].string.text = _cupsStrRetain(printer->job_sheets[1]);
    
  •  ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]);
    
  •  ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]);
    

    }

    job->job_sheets = attr;
    @@ -1881,7 +1842,7 @@
    * Force the leading banner to have the classification on it...
    */

  •      cupsdSetString(&attr->values[0].string.text, Classification);
    
  •      ippSetString(job->attrs, &attr, 0, Classification);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,none", "
    @@ -1898,7 +1859,7 @@

    • Can't put two different security markings on the same document!
      */
  •      cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
    
  •      ippSetString(job->attrs, &attr, 1, attr->values[0].string.text);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,%s", "
    @@ -1938,18 +1899,18 @@
    if (attr->num_values > 1 &&
    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
    {

  •      cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •      cupsdSetString(&(attr->values[1].string.text), Classification);
    
  •      ippSetString(job->attrs, &attr, 0, Classification);
    
  •      ippSetString(job->attrs, &attr, 1, Classification);
    

    }
    else
    {
    if (attr->num_values == 1 ||
    strcmp(attr->values[0].string.text, "none"))

  •        cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •        ippSetString(job->attrs, &attr, 0, Classification);
    
       if (attr->num_values > 1 &&
      strcmp(attr->values[1].string.text, "none"))
    
  •        cupsdSetString(&(attr->values[1].string.text), Classification);
    
  •   ippSetString(job->attrs, &attr, 1, Classification);
     }
    
     if (attr->num_values > 1)
    

    @@ -3160,8 +3121,8 @@

    if (attr)
    {

  • attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");

  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);

  • ippSetString(job->attrs, &attr, 0, "no-hold");
    }

/*
@@ -8388,11 +8349,7 @@
filetype->type);

if (format)

  • {

- _cupsStrFree(format->values[0].string.text);

  •  format->values[0].string.text = _cupsStrAlloc(mimetype);
    
  • }

  •  ippSetString(con->request, &format, 0, mimetype);
    

    else
    ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
    "document-format", NULL, mimetype);
    @@ -8927,11 +8884,9 @@

    if (attr)
    {

  • _cupsStrFree(attr->values[0].string.text);

  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);

  • ippSetString(job->attrs, &attr, 0, "no-hold");

  • attr->value_tag = IPP_TAG_KEYWORD;

- attr->values[0].string.text = _cupsStrAlloc("no-hold");

 cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
               "Job job-hold-until value changed by user.");
 ippSetString(job->attrs, &job->reasons, 0, "none");

@@ -9617,11 +9572,7 @@

 if ((jformat = ippFindAttribute(job->attrs, "document-format",
                                 IPP_TAG_MIMETYPE)) != NULL)
  • {

- _cupsStrFree(jformat->values[0].string.text);

  •  jformat->values[0].string.text = _cupsStrAlloc(mimetype);
    
  • }

  •  ippSetString(job->attrs, &jformat, 0, mimetype);
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
    "document-format", NULL, mimetype);

    Index: scheduler/job.c

    --- scheduler/job.c (revision 12550)
    +++ scheduler/job.c (revision 12588)
    @@ -430,7 +430,7 @@

       if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
                               IPP_TAG_URI)) != NULL)
    
  •        cupsdSetString(&attr->values[0].string.text, printer->uri);
    
  •        ippSetString(job->attrs, &attr, 0, printer->uri);
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
    "job-actual-printer-uri", NULL, printer->uri);
    @@ -2050,7 +2050,7 @@

    if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
    IPP_TAG_URI)) != NULL)

  • cupsdSetString(&(attr->values[0].string.text), p->uri);

  • ippSetString(job->attrs, &attr, 0, p->uri);

cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
"Job #%d moved from %s to %s.", job->id, olddest,
@@ -2241,7 +2241,7 @@
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);

if (attr)

  •  cupsdSetString(&(attr->values[0].string.text), when);
    
  •  ippSetString(job->attrs, &attr, 0, when);
    

    else
    attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
    "job-hold-until", NULL, when);
    @@ -2495,8 +2495,8 @@

    if (attr)
    {

  • attr->value_tag = IPP_TAG_KEYWORD;
    
  • cupsdSetString(&(attr->values[0].string.text), "no-hold");
    
  • ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);
    
  • ippSetString(job->attrs, &attr, 0, "no-hold");
    

    }

    default :
    @@ -4443,7 +4443,7 @@
    "job-printer-state-message",
    IPP_TAG_TEXT);
    if (job->printer_message)

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");

  • ippSetString(job->attrs, &job->printer_message, 0, "");

ippSetString(job->attrs, &job->reasons, 0, "job-printing");
cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL);
@@ -5021,15 +5021,14 @@
if (job->state_value != IPP_JOB_PROCESSING &&
job->status_level == CUPSD_LOG_INFO)
{

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");
  • ippSetString(job->attrs, &job->printer_message, 0, "");

job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
else if (job->printer->state_message[0] && do_message)
{

  • cupsdSetString(&(job->printer_message->values[0].string.text),
  •      job->printer->state_message);
    
  • ippSetString(job->attrs, &job->printer_message, 0, job->printer->state_message);

job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);

@michaelrsweet
Copy link
Collaborator Author

"str4609-1.5.patch":

Index: cgi-bin/ipp-var.c

--- cgi-bin/ipp-var.c (revision 12588)
+++ cgi-bin/ipp-var.c (working copy)
@@ -1230,21 +1230,7 @@
* Rewrite URIs...
*/

  •          if (!strcmp(name, "member_uris"))
    
  •     {
    

- char url[1024]; /* URL for class member... */

  •   cgiRewriteURL(attr->values[i].string.text, url,
    

- sizeof(url), NULL);

  •            snprintf(valptr, sizeof(value) - (valptr - value),
    
  •            "<A HREF=\"%s\">%s</A>", url,
    
  •        strrchr(attr->values[i].string.text, '/') + 1);
    
  •     }
    
  •     else
    
  •   cgiRewriteURL(attr->values[i].string.text, valptr,
    
  •                 sizeof(value) - (valptr - value), NULL);
    
  •     cgiRewriteURL(attr->values[i].string.text, valptr, sizeof(value) - (valptr - value), NULL);
           break;
         }
    

Index: cgi-bin/template.c

--- cgi-bin/template.c (revision 12588)
+++ cgi-bin/template.c (working copy)
@@ -659,39 +659,7 @@
while (_s)
{
if (_s == '<')

  • {
  • /*
    
  •  \* Pass <A HREF="url"> and </A>, otherwise quote it...
    

- */

  •  if (!_cups_strncasecmp(s, "<A HREF=\"", 9))
    
  •  {
    
  •    fputs("<A HREF=\"", out);
    

- s += 9;

  • while (*s && *s != '"')
  • {
  •      if (*s == '&')
    
  •        fputs("&amp;", out);
    
  • else
    

- putc(*s, out);

  • s ++;
    

- }

  •    if (*s)
    

- s ++;

  • fputs("">", out);

  •  }
    
  •  else if (!_cups_strncasecmp(s, "</A>", 4))
    
  •  {
    
  •    fputs("</A>", out);
    
  • s += 3;

  •  }
    
  •  else
    
  •    fputs("&lt;", out);
    
  • }

  •  fputs("&lt;", out);
    

    else if (_s == '>')
    fputs(">", out);
    else if (_s == '"')

    Index: scheduler/ipp.c

    --- scheduler/ipp.c (revision 12588)
    +++ scheduler/ipp.c (working copy)
    @@ -509,8 +509,8 @@
    * Remote unauthenticated user masquerading as local root...
    */

  •   _cupsStrFree(username->values[0].string.text);
    
  •   username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    
  •        _cupsStrFree(username->values[0].string.text);
    
  •        username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    

    }
    }

@@ -1648,7 +1648,10 @@
cupsdSetString(&job->username, con->username);

 if (attr)
  •  cupsdSetString(&attr->values[0].string.text, con->username);
    
  • {
  •  _cupsStrFree(attr->values[0].string.text);
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->username);
    
  • }
    }
    else if (attr)
    {
    @@ -1699,48 +1702,11 @@
  • Also, we can only have 1 value and it must be a name value.
    */
  •  switch (attr->value_tag)
    
  •  {
    
  •    case IPP_TAG_STRING :
    
  • case IPP_TAG_TEXTLANG :
  • case IPP_TAG_NAMELANG :
  • case IPP_TAG_TEXT :
  • case IPP_TAG_NAME :
  • case IPP_TAG_KEYWORD :
  • case IPP_TAG_URI :
  • case IPP_TAG_URISCHEME :
  • case IPP_TAG_CHARSET :
  • case IPP_TAG_LANGUAGE :
  • case IPP_TAG_MIMETYPE :
  •  /*
    
  •   \* Free old strings...
    

- */

  •   for (i = 0; i < attr->num_values; i ++)
    
  •   {
    
  •     _cupsStrFree(attr->values[i].string.text);
    
  •     attr->values[i].string.text = NULL;
    
  •     if (attr->values[i].string.charset)
    
  •     {
    
  •   _cupsStrFree(attr->values[i].string.charset);
    
  •   attr->values[i].string.charset = NULL;
    
  •     }
    

- }

  • default :
  •        break;
    

- }

  • /*
    
  •  \* Use the default connection hostname instead...
    

- */

  •  attr->value_tag             = IPP_TAG_NAME;
    
  •  attr->num_values            = 1;
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->http.hostname);
    
  •  ippDeleteAttribute(job->attrs, attr);
    
  •  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http.hostname);
    

    }

  • attr->group_tag = IPP_TAG_JOB;

  • else

  •  attr->group_tag = IPP_TAG_JOB;
    

    }
    else
    {
    @@ -1832,8 +1798,8 @@

    attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
    2, NULL, NULL);

  •  attr->values[0].string.text = _cupsStrRetain(printer->job_sheets[0]);
    
  •  attr->values[1].string.text = _cupsStrRetain(printer->job_sheets[1]);
    
  •  attr->values[0].string.text = _cupsStrAlloc(printer->job_sheets[0]);
    
  •  attr->values[1].string.text = _cupsStrAlloc(printer->job_sheets[1]);
    

    }

    job->job_sheets = attr;
    @@ -1859,7 +1825,8 @@
    * Force the leading banner to have the classification on it...
    */

  •      cupsdSetString(&attr->values[0].string.text, Classification);
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc(Classification);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,none", "
    @@ -1876,7 +1843,8 @@

    • Can't put two different security markings on the same document!
      */
  •      cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
    
  • _cupsStrFree(attr->values[1].string.text);
    
  • attr->values[1].string.text = _cupsStrAlloc(attr->values[0].string.text);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,%s", "
    @@ -1916,18 +1884,26 @@
    if (attr->num_values > 1 &&
    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
    {

  •      cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •      cupsdSetString(&(attr->values[1].string.text), Classification);
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc(Classification);
    
  • _cupsStrFree(attr->values[1].string.text);
    
  • attr->values[1].string.text = _cupsStrAlloc(Classification);
    

    }
    else
    {
    if (attr->num_values == 1 ||
    strcmp(attr->values[0].string.text, "none"))

  •        cupsdSetString(&(attr->values[0].string.text), Classification);
    
  • {
    
  •   _cupsStrFree(attr->values[0].string.text);
    
  •   attr->values[0].string.text = _cupsStrAlloc(Classification);
    
  • }
    
       if (attr->num_values > 1 &&
      strcmp(attr->values[1].string.text, "none"))
    
  •        cupsdSetString(&(attr->values[1].string.text), Classification);
    
  • {
    
  •   _cupsStrFree(attr->values[1].string.text);
    
  •   attr->values[1].string.text = _cupsStrAlloc(Classification);
    
  • }
     }
    
     if (attr->num_values > 1)
    

    @@ -4150,7 +4126,8 @@
    if (attr)
    {
    attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");

  • _cupsStrFree(attr->values[0].string.text);

  • attr->values[0].string.text = _cupsStrAlloc("no-hold");
    }

/*
@@ -9491,7 +9468,6 @@
if (format)
{

_cupsStrFree(format->values[0].string.text);

 format->values[0].string.text = _cupsStrAlloc(mimetype);

}
else
@@ -10028,9 +10004,8 @@

if (attr)
{

  • attr->value_tag = IPP_TAG_KEYWORD;
    _cupsStrFree(attr->values[0].string.text);
  • attr->value_tag = IPP_TAG_KEYWORD;
    attr->values[0].string.text = _cupsStrAlloc("no-hold");

cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
@@ -10719,7 +10694,6 @@
IPP_TAG_MIMETYPE)) != NULL)
{

_cupsStrFree(jformat->values[0].string.text);

 jformat->values[0].string.text = _cupsStrAlloc(mimetype);

}
else

Index: scheduler/job.c

--- scheduler/job.c (revision 12588)
+++ scheduler/job.c (working copy)
@@ -406,7 +406,10 @@

   if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
                           IPP_TAG_URI)) != NULL)
  •        cupsdSetString(&attr->values[0].string.text, printer->uri);
    
  •      {
    
  •        _cupsStrFree(attr->values[0].string.text);
    
  •        attr->values[0].string.text = _cupsStrAlloc(printer->uri);
    
  •      }
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
    "job-actual-printer-uri", NULL, printer->uri);
    @@ -1846,7 +1849,7 @@
    }
    else if (i >= (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0])))
    break;

    • if (!strcmp(line, "username"))
      cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s", data);
      else if (!strcmp(line, "domain"))
      @@ -1950,7 +1953,10 @@

    if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
    IPP_TAG_URI)) != NULL)

  • cupsdSetString(&(attr->values[0].string.text), p->uri);

  • {

  • _cupsStrFree(attr->values[0].string.text);

  • attr->values[0].string.text = _cupsStrAlloc(p->uri);

  • }

cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
"Job #%d moved from %s to %s.", job->id, olddest,
@@ -2153,7 +2159,10 @@
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);

if (attr)

  •  cupsdSetString(&(attr->values[0].string.text), when);
    
  • {

  •  _cupsStrFree(attr->values[0].string.text);
    
  •  attr->values[0].string.text = _cupsStrAlloc(when);
    
  • }
    else
    attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
    "job-hold-until", NULL, when);
    @@ -2399,7 +2408,8 @@
    if (attr)
    {
    attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc("no-hold");
    

    }

    default :
    @@ -4146,7 +4156,10 @@
    "job-printer-state-message",
    IPP_TAG_TEXT);
    if (job->printer_message)

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");

  • {

  • _cupsStrFree(job->printer_message->values[0].string.text);

  • job->printer_message->values[0].string.text = _cupsStrAlloc("");

  • }

cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL);
cupsdSetPrinterState(printer, IPP_PRINTER_PROCESSING, 0);
@@ -4708,10 +4721,15 @@

if (job->state_value != IPP_JOB_PROCESSING &&
job->status_level == CUPSD_LOG_INFO)

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");
  • {
  • _cupsStrFree(job->printer_message->values[0].string.text);
  • job->printer_message->values[0].string.text = _cupsStrAlloc("");
  • }
    else if (job->printer->state_message[0] && do_message)
  • cupsdSetString(&(job->printer_message->values[0].string.text),
  •      job->printer->state_message);
    
  • {
  • _cupsStrFree(job->printer_message->values[0].string.text);
  • job->printer_message->values[0].string.text = _cupsStrAlloc(job->printer->state_message);
  • }

/*

  • ... and the printer-state-reasons value...

@michaelrsweet
Copy link
Collaborator Author

"str4609-1.4.patch":

Index: cgi-bin/ipp-var.c

--- cgi-bin/ipp-var.c (revision 12588)
+++ cgi-bin/ipp-var.c (working copy)
@@ -1230,21 +1230,7 @@
* Rewrite URIs...
*/

  •          if (!strcmp(name, "member_uris"))
    
  •     {
    

- char url[1024]; /* URL for class member... */

  •   cgiRewriteURL(attr->values[i].string.text, url,
    

- sizeof(url), NULL);

  •            snprintf(valptr, sizeof(value) - (valptr - value),
    
  •            "<A HREF=\"%s\">%s</A>", url,
    
  •        strrchr(attr->values[i].string.text, '/') + 1);
    
  •     }
    
  •     else
    
  •   cgiRewriteURL(attr->values[i].string.text, valptr,
    
  •                 sizeof(value) - (valptr - value), NULL);
    
  •     cgiRewriteURL(attr->values[i].string.text, valptr, sizeof(value) - (valptr - value), NULL);
           break;
         }
    

Index: cgi-bin/template.c

--- cgi-bin/template.c (revision 12588)
+++ cgi-bin/template.c (working copy)
@@ -659,39 +659,7 @@
while (_s)
{
if (_s == '<')

  • {
  • /*
    
  •  \* Pass <A HREF="url"> and </A>, otherwise quote it...
    

- */

  •  if (!strncasecmp(s, "<A HREF=\"", 9))
    
  •  {
    
  •    fputs("<A HREF=\"", out);
    

- s += 9;

  • while (*s && *s != '"')
  • {
  •      if (*s == '&')
    
  •        fputs("&amp;", out);
    
  • else
    

- putc(*s, out);

  • s ++;
    

- }

  •    if (*s)
    

- s ++;

  • fputs("">", out);

  •  }
    
  •  else if (!strncasecmp(s, "</A>", 4))
    
  •  {
    
  •    fputs("</A>", out);
    
  • s += 3;

  •  }
    
  •  else
    
  •    fputs("&lt;", out);
    
  • }

  •  fputs("&lt;", out);
    

    else if (_s == '>')
    fputs(">", out);
    else if (_s == '"')

    Index: scheduler/ipp.c

    --- scheduler/ipp.c (revision 12588)
    +++ scheduler/ipp.c (working copy)
    @@ -498,8 +498,8 @@
    * Remote unauthenticated user masquerading as local root...
    */

  •   _cupsStrFree(username->values[0].string.text);
    
  •   username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    
  •        _cupsStrFree(username->values[0].string.text);
    
  •        username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    

    }
    }

@@ -1638,7 +1638,10 @@
cupsdSetString(&job->username, con->username);

 if (attr)
  •  cupsdSetString(&attr->values[0].string.text, con->username);
    
  • {
  •  _cupsStrFree(attr->values[0].string.text);
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->username);
    
  • }
    }
    else if (attr)
    {
    @@ -1689,48 +1692,11 @@
  • Also, we can only have 1 value and it must be a name value.
    */
  •  switch (attr->value_tag)
    
  •  {
    
  •    case IPP_TAG_STRING :
    
  • case IPP_TAG_TEXTLANG :
  • case IPP_TAG_NAMELANG :
  • case IPP_TAG_TEXT :
  • case IPP_TAG_NAME :
  • case IPP_TAG_KEYWORD :
  • case IPP_TAG_URI :
  • case IPP_TAG_URISCHEME :
  • case IPP_TAG_CHARSET :
  • case IPP_TAG_LANGUAGE :
  • case IPP_TAG_MIMETYPE :
  •  /*
    
  •   \* Free old strings...
    

- */

  •   for (i = 0; i < attr->num_values; i ++)
    
  •   {
    
  •     _cupsStrFree(attr->values[i].string.text);
    
  •     attr->values[i].string.text = NULL;
    
  •     if (attr->values[i].string.charset)
    
  •     {
    
  •   _cupsStrFree(attr->values[i].string.charset);
    
  •   attr->values[i].string.charset = NULL;
    
  •     }
    

- }

  • default :
  •        break;
    

- }

  • /*
    
  •  \* Use the default connection hostname instead...
    

- */

  •  attr->value_tag             = IPP_TAG_NAME;
    
  •  attr->num_values            = 1;
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->http.hostname);
    
  •  ippDeleteAttribute(job->attrs, attr);
    
  •  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http.hostname);
    

    }

  • attr->group_tag = IPP_TAG_JOB;

  • else

  •  attr->group_tag = IPP_TAG_JOB;
    

    }
    else
    {
    @@ -1822,8 +1788,8 @@

    attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
    2, NULL, NULL);

  •  attr->values[0].string.text = _cupsStrRetain(printer->job_sheets[0]);
    
  •  attr->values[1].string.text = _cupsStrRetain(printer->job_sheets[1]);
    
  •  attr->values[0].string.text = _cupsStrAlloc(printer->job_sheets[0]);
    
  •  attr->values[1].string.text = _cupsStrAlloc(printer->job_sheets[1]);
    

    }

    job->job_sheets = attr;
    @@ -1849,7 +1815,8 @@
    * Force the leading banner to have the classification on it...
    */

  •      cupsdSetString(&attr->values[0].string.text, Classification);
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc(Classification);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,none", "
    @@ -1866,7 +1833,8 @@

    • Can't put two different security markings on the same document!
      */
  •      cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
    
  • _cupsStrFree(attr->values[1].string.text);
    
  • attr->values[1].string.text = _cupsStrAlloc(attr->values[0].string.text);
    

    cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
    "job-sheets="%s,%s", "
    @@ -1906,18 +1874,26 @@
    if (attr->num_values > 1 &&
    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
    {

  •      cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •      cupsdSetString(&(attr->values[1].string.text), Classification);
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc(Classification);
    
  • _cupsStrFree(attr->values[1].string.text);
    
  • attr->values[1].string.text = _cupsStrAlloc(Classification);
    

    }
    else
    {
    if (attr->num_values == 1 ||
    strcmp(attr->values[0].string.text, "none"))

  •        cupsdSetString(&(attr->values[0].string.text), Classification);
    
  • {
    
  •   _cupsStrFree(attr->values[0].string.text);
    
  •   attr->values[0].string.text = _cupsStrAlloc(Classification);
    
  • }
    
       if (attr->num_values > 1 &&
      strcmp(attr->values[1].string.text, "none"))
    
  •        cupsdSetString(&(attr->values[1].string.text), Classification);
    
  • {
    
  •   _cupsStrFree(attr->values[1].string.text);
    
  •   attr->values[1].string.text = _cupsStrAlloc(Classification);
    
  • }
     }
    
     if (attr->num_values > 1)
    

    @@ -3845,7 +3821,8 @@
    if (attr)
    {
    attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");

  • _cupsStrFree(attr->values[0].string.text);

  • attr->values[0].string.text = _cupsStrAlloc("no-hold");
    }

/*
@@ -8832,7 +8809,6 @@
if (format)
{

_cupsStrFree(format->values[0].string.text);

 format->values[0].string.text = _cupsStrAlloc(mimetype);

}
else
@@ -9371,9 +9347,8 @@

if (attr)
{

  • attr->value_tag = IPP_TAG_KEYWORD;
    _cupsStrFree(attr->values[0].string.text);
  • attr->value_tag = IPP_TAG_KEYWORD;
    attr->values[0].string.text = _cupsStrAlloc("no-hold");

cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
@@ -10065,7 +10040,6 @@
IPP_TAG_MIMETYPE)) != NULL)
{

_cupsStrFree(jformat->values[0].string.text);

 jformat->values[0].string.text = _cupsStrAlloc(mimetype);

}
else

Index: scheduler/job.c

--- scheduler/job.c (revision 12588)
+++ scheduler/job.c (working copy)
@@ -397,7 +397,10 @@

   if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
                           IPP_TAG_URI)) != NULL)
  •        cupsdSetString(&attr->values[0].string.text, printer->uri);
    
  •      {
    
  •        _cupsStrFree(attr->values[0].string.text);
    
  •        attr->values[0].string.text = _cupsStrAlloc(printer->uri);
    
  •      }
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
    "job-actual-printer-uri", NULL, printer->uri);
    @@ -1830,7 +1833,10 @@

    if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
    IPP_TAG_URI)) != NULL)

  • cupsdSetString(&(attr->values[0].string.text), p->uri);

  • {

  • _cupsStrFree(attr->values[0].string.text);

  • attr->values[0].string.text = _cupsStrAlloc(p->uri);

  • }

cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
"Job #%d moved from %s to %s.", job->id, olddest,
@@ -2026,7 +2032,10 @@
attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);

if (attr)

  •  cupsdSetString(&(attr->values[0].string.text), when);
    
  • {

  •  _cupsStrFree(attr->values[0].string.text);
    
  •  attr->values[0].string.text = _cupsStrAlloc(when);
    
  • }
    else
    attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
    "job-hold-until", NULL, when);
    @@ -2272,7 +2281,8 @@
    if (attr)
    {
    attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc("no-hold");
    

    }

    default :
    @@ -3989,7 +3999,10 @@
    job->status_level = CUPSD_LOG_INFO;

    if (job->printer_message)

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");

  • {

  • _cupsStrFree(job->printer_message->values[0].string.text);

  • job->printer_message->values[0].string.text = _cupsStrAlloc("");

  • }

/*

  • Create the backchannel pipes and make them non-blocking...
    @@ -4547,10 +4560,15 @@

if (job->state_value != IPP_JOB_PROCESSING &&
job->status_level == CUPSD_LOG_INFO)

  • cupsdSetString(&(job->printer_message->values[0].string.text), "");
  • {
  • _cupsStrFree(job->printer_message->values[0].string.text);
  • job->printer_message->values[0].string.text = _cupsStrAlloc("");
  • }
    else if (job->printer->state_message[0] && do_message)
  • cupsdSetString(&(job->printer_message->values[0].string.text),
  •      job->printer->state_message);
    
  • {
  • _cupsStrFree(job->printer_message->values[0].string.text);
  • job->printer_message->values[0].string.text = _cupsStrAlloc(job->printer->state_message);
  • }

/*

  • ... and the printer-state-reasons value...

@michaelrsweet
Copy link
Collaborator Author

"str4609-1.3.patch":

Index: cgi-bin/ipp-var.c

--- cgi-bin/ipp-var.c (revision 12588)
+++ cgi-bin/ipp-var.c (working copy)
@@ -1048,21 +1048,7 @@
* Rewrite URIs...
*/

  •          if (!strcmp(name, "member_uris"))
    
  •     {
    

- char url[1024]; /* URL for class member... */

  •   cgiRewriteURL(attr->values[i].string.text, url,
    

- sizeof(url), NULL);

  •            snprintf(valptr, sizeof(value) - (valptr - value),
    
  •            "<A HREF=\"%s\">%s</A>", url,
    
  •        strrchr(attr->values[i].string.text, '/') + 1);
    
  •     }
    
  •     else
    
  •   cgiRewriteURL(attr->values[i].string.text, valptr,
    
  •                 sizeof(value) - (valptr - value), NULL);
    
  •     cgiRewriteURL(attr->values[i].string.text, valptr, sizeof(value) - (valptr - value), NULL);
           break;
         }
    

Index: cgi-bin/template.c

--- cgi-bin/template.c (revision 12588)
+++ cgi-bin/template.c (working copy)
@@ -602,39 +602,7 @@
while (_s)
{
if (_s == '<')

  • {
  • /*
    
  •  \* Pass <A HREF="url"> and </A>, otherwise quote it...
    

- */

  •  if (!strncasecmp(s, "<A HREF=\"", 9))
    
  •  {
    
  •    fputs("<A HREF=\"", out);
    

- s += 9;

  • while (*s && *s != '"')
  • {
  •      if (*s == '&')
    
  •        fputs("&amp;", out);
    
  • else
    

- putc(*s, out);

  • s ++;
    

- }

  •    if (*s)
    

- s ++;

  • fputs("">", out);

  •  }
    
  •  else if (!strncasecmp(s, "</A>", 4))
    
  •  {
    
  •    fputs("</A>", out);
    
  • s += 3;

  •  }
    
  •  else
    
  •    fputs("&lt;", out);
    
  • }

  •  fputs("&lt;", out);
    

    else if (_s == '>')
    fputs(">", out);
    else if (_s == '"')

    Index: scheduler/ipp.c

    --- scheduler/ipp.c (revision 12588)
    +++ scheduler/ipp.c (working copy)
    @@ -463,8 +463,8 @@
    * Remote unauthenticated user masquerading as local root...
    */

  •   _cupsStrFree(username->values[0].string.text);
    
  •   username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    
  •        _cupsStrFree(username->values[0].string.text);
    
  •        username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    

    }
    }

@@ -1517,7 +1517,10 @@
cupsdSetString(&job->username, con->username);

 if (attr)
  •  cupsdSetString(&attr->values[0].string.text, con->username);
    
  • {
  •  _cupsStrFree(attr->values[0].string.text);
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->username);
    
  • }
    }
    else if (attr)
    {
    @@ -1568,48 +1571,11 @@
  • Also, we can only have 1 value and it must be a name value.
    */
  •  switch (attr->value_tag)
    
  •  {
    
  •    case IPP_TAG_STRING :
    
  • case IPP_TAG_TEXTLANG :
  • case IPP_TAG_NAMELANG :
  • case IPP_TAG_TEXT :
  • case IPP_TAG_NAME :
  • case IPP_TAG_KEYWORD :
  • case IPP_TAG_URI :
  • case IPP_TAG_URISCHEME :
  • case IPP_TAG_CHARSET :
  • case IPP_TAG_LANGUAGE :
  • case IPP_TAG_MIMETYPE :
  •  /*
    
  •   \* Free old strings...
    

- */

  •   for (i = 0; i < attr->num_values; i ++)
    
  •   {
    
  •     _cupsStrFree(attr->values[i].string.text);
    
  •     attr->values[i].string.text = NULL;
    
  •     if (attr->values[i].string.charset)
    
  •     {
    
  •   _cupsStrFree(attr->values[i].string.charset);
    
  •   attr->values[i].string.charset = NULL;
    
  •     }
    

- }

  • default :
  •        break;
    

- }

  • /*
    
  •  \* Use the default connection hostname instead...
    

- */

  •  attr->value_tag             = IPP_TAG_NAME;
    
  •  attr->num_values            = 1;
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->http.hostname);
    
  •  ippDeleteAttribute(job->attrs, attr);
    
  •  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http.hostname);
    

    }

  • attr->group_tag = IPP_TAG_JOB;

  • else

  •  attr->group_tag = IPP_TAG_JOB;
    

    }
    else
    {
    @@ -1731,7 +1697,8 @@
    * Force the leading banner to have the classification on it...
    */

  •      cupsdSetString(&attr->values[0].string.text, Classification);
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc(Classification);
    

    cupsdLogMessage(CUPSD_LOG_NOTICE, "[Job %d] CLASSIFICATION FORCED "
    "job-sheets="%s,none", "
    @@ -1748,7 +1715,8 @@

    • Can't put two different security markings on the same document!
      */
  •      cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
    
  • _cupsStrFree(attr->values[1].string.text);
    
  • attr->values[1].string.text = _cupsStrAlloc(attr->values[0].string.text);
    

    cupsdLogMessage(CUPSD_LOG_NOTICE, "[Job %d] CLASSIFICATION FORCED "
    "job-sheets="%s,%s", "
    @@ -1788,18 +1756,26 @@
    if (attr->num_values > 1 &&
    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
    {

  •      cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •      cupsdSetString(&(attr->values[1].string.text), Classification);
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc(Classification);
    
  • _cupsStrFree(attr->values[1].string.text);
    
  • attr->values[1].string.text = _cupsStrAlloc(Classification);
    

    }
    else
    {
    if (attr->num_values == 1 ||
    strcmp(attr->values[0].string.text, "none"))

  •        cupsdSetString(&(attr->values[0].string.text), Classification);
    
  • {
    
  •   _cupsStrFree(attr->values[0].string.text);
    
  •   attr->values[0].string.text = _cupsStrAlloc(Classification);
    
  • }
    
       if (attr->num_values > 1 &&
      strcmp(attr->values[1].string.text, "none"))
    
  •        cupsdSetString(&(attr->values[1].string.text), Classification);
    
  • {
    
  •   _cupsStrFree(attr->values[1].string.text);
    
  •   attr->values[1].string.text = _cupsStrAlloc(Classification);
    
  • }
     }
    
     if (attr->num_values > 1)
    

    @@ -3088,7 +3064,8 @@
    if (attr)
    {
    attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");

  • _cupsStrFree(attr->values[0].string.text);

  • attr->values[0].string.text = _cupsStrAlloc("no-hold");
    }

/*
@@ -7665,7 +7642,6 @@
if (format)
{

_cupsStrFree(format->values[0].string.text);

 format->values[0].string.text = _cupsStrAlloc(mimetype);

}
else
@@ -8137,9 +8113,8 @@

if (attr)
{

  • attr->value_tag = IPP_TAG_KEYWORD;
    _cupsStrFree(attr->values[0].string.text);
  • attr->value_tag = IPP_TAG_KEYWORD;
    attr->values[0].string.text = _cupsStrAlloc("no-hold");

cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, job->printer, job,
@@ -8894,7 +8869,6 @@
if (jformat)
{

_cupsStrFree(jformat->values[0].string.text);

 jformat->values[0].string.text = _cupsStrAlloc(mimetype);

}
else

Index: scheduler/job.c

--- scheduler/job.c (revision 12588)
+++ scheduler/job.c (working copy)
@@ -393,7 +393,8 @@
if (attr)
{
attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");
  • _cupsStrFree(attr->values[0].string.text);
  • attr->values[0].string.text = _cupsStrAlloc("no-hold");
    cupsdSaveJob(job);
    }
    }
    @@ -457,7 +458,10 @@
   if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
                           IPP_TAG_URI)) != NULL)
  •        cupsdSetString(&attr->values[0].string.text, printer->uri);
    
  •      {
    
  •        _cupsStrFree(attr->values[0].string.text);
    
  •        attr->values[0].string.text = _cupsStrAlloc(printer->uri);
    
  •      }
    
    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
    "job-actual-printer-uri", NULL, printer->uri);
    @@ -468,7 +472,7 @@
    ((printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is remote /
    !printer->job)) /
    and not printing */
    {
  • /*
  • /*
  • Clear any message and reasons for the queue...
    */

@@ -761,8 +765,8 @@
if (attr)
{
attr->value_tag = IPP_TAG_KEYWORD;

  •   cupsdSetString(&(attr->values[0].string.text),
    
  •                  "auth-info-required");
    
  •   _cupsStrFree(attr->values[0].string.text);
    
  •   attr->values[0].string.text = _cupsStrAlloc("auth-info-required");
    

    }

    job->state->values[0].integer = IPP_JOB_HELD;
    @@ -1350,7 +1354,10 @@

    if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
    IPP_TAG_URI)) != NULL)

  • cupsdSetString(&(attr->values[0].string.text), p->uri);

  • {

  • _cupsStrFree(attr->values[0].string.text);

  • attr->values[0].string.text = _cupsStrAlloc(p->uri);

  • }

cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
"Job #%d moved from %s to %s.", job->id, olddest,
@@ -2425,7 +2432,10 @@
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-hold-until",
NULL, holdstr);
else

  • cupsdSetString(&attr->values[0].string.text, holdstr);
  • {
  • _cupsStrFree(attr->values[0].string.text);
  • attr->values[0].string.text = _cupsStrAlloc(holdstr);
  • }

cupsdSaveJob(job);
}
@@ -3880,9 +3890,10 @@
*/

if (job->printer->state_message[0])

  • cupsdSetString(&(job->printer_message->values[0].string.text),

- job->printer->state_message);

  • {
  • _cupsStrFree(job->printer_message->values[0].string.text);
  • job->printer_message->values[0].string.text = _cupsStrAlloc(job->printer->state_message);
  • }
    /*
  • ... and the printer-state-reasons value...
    */

@michaelrsweet
Copy link
Collaborator Author

"str4609-1.2.patch":

Index: cgi-bin/ipp-var.c

--- cgi-bin/ipp-var.c (revision 12588)
+++ cgi-bin/ipp-var.c (working copy)
@@ -904,21 +904,7 @@
* Rewrite URIs...
*/

  •          if (!strcmp(name, "member_uris"))
    
  •     {
    

- char url[1024]; /* URL for class member... */

  •   cgiRewriteURL(attr->values[i].string.text, url,
    

- sizeof(url), NULL);

  •            snprintf(valptr, sizeof(value) - (valptr - value),
    
  •            "<A HREF=\"%s\">%s</A>", url,
    
  •        strrchr(attr->values[i].string.text, '/') + 1);
    
  •     }
    
  •     else
    
  •   cgiRewriteURL(attr->values[i].string.text, valptr,
    
  •                 sizeof(value) - (valptr - value), NULL);
    
  •     cgiRewriteURL(attr->values[i].string.text, valptr, sizeof(value) - (valptr - value), NULL);
           break;
         }
    

Index: cgi-bin/template.c

--- cgi-bin/template.c (revision 12588)
+++ cgi-bin/template.c (working copy)
@@ -602,39 +602,7 @@
while (_s)
{
if (_s == '<')

  • {
  • /*
    
  •  \* Pass <A HREF="url"> and </A>, otherwise quote it...
    

- */

  •  if (!strncasecmp(s, "<A HREF=\"", 9))
    
  •  {
    
  •    fputs("<A HREF=\"", out);
    

- s += 9;

  • while (*s && *s != '"')
  • {
  •      if (*s == '&')
    
  •        fputs("&amp;", out);
    
  • else
    

- putc(*s, out);

  • s ++;
    

- }

  •    if (*s)
    

- s ++;

  • fputs("">", out);
  •  }
    
  •  else if (!strncasecmp(s, "</A>", 4))
    
  •  {
    
  •    fputs("</A>", out);
    
  • s += 3;
  •  }
    
  •  else
    
  •    fputs("&lt;", out);
    
  • }
  •  fputs("&lt;", out);
    

    else if (_s == '>')
    fputs(">", out);
    else if (_s == '"')
    Index: scheduler/ipp.c

    --- scheduler/ipp.c (revision 12588)
    +++ scheduler/ipp.c (working copy)
    @@ -233,7 +233,7 @@
    /*
    • Then validate the request header and required attributes...
      _/

      if (con->request->request.any.version[0] != 1)
      {
      /_
      @@ -250,7 +250,7 @@
      _("Bad request version number %d.%d!"),
      con->request->request.any.version[0],
      con->request->request.any.version[1]);
  • }
  • }
    else if (!con->request->attrs)
    {
    cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
    @@ -384,7 +384,7 @@
    cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow...");

for (attr = con->request->attrs; attr; attr = attr->next)

  • cupsdLogMessage(CUPSD_LOG_DEBUG,
    
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
              "attr \"%s\": group_tag = %x, value_tag = %x",
              attr->name ? attr->name : "(null)", attr->group_tag,
          attr->value_tag);
    

    @@ -416,8 +416,8 @@
    * Remote unauthenticated user masquerading as local root...
    */

  •   _cupsStrFree(username->values[0].string.text);
    
  •   username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    
  •        _cupsStrFree(username->values[0].string.text);
    
  •        username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
    

    }
    }

@@ -1268,7 +1268,7 @@
{
for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++)
{

  •  if (attr->values[i].range.lower < lowerpagerange ||
    
  •  if (attr->values[i].range.lower < lowerpagerange ||
    

    attr->values[i].range.lower > attr->values[i].range.upper)
    {
    send_ipp_status(con, IPP_BAD_REQUEST,
    @@ -1354,7 +1354,10 @@
    cupsdSetString(&job->username, con->username);

    if (attr)

  •  cupsdSetString(&attr->values[0].string.text, con->username);
    
  • {

  •  _cupsStrFree(attr->values[0].string.text);
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->username);
    
  • }

save_auth_info(con, job);
}
@@ -1395,48 +1398,11 @@

  • Also, we can only have 1 value and it must be a name value.
    */
  •  switch (attr->value_tag)
    
  •  {
    
  •    case IPP_TAG_STRING :
    
  • case IPP_TAG_TEXTLANG :
  • case IPP_TAG_NAMELANG :
  • case IPP_TAG_TEXT :
  • case IPP_TAG_NAME :
  • case IPP_TAG_KEYWORD :
  • case IPP_TAG_URI :
  • case IPP_TAG_URISCHEME :
  • case IPP_TAG_CHARSET :
  • case IPP_TAG_LANGUAGE :
  • case IPP_TAG_MIMETYPE :
  •  /*
    
  •   \* Free old strings...
    

- */

  •   for (i = 0; i < attr->num_values; i ++)
    
  •   {
    
  •     _cupsStrFree(attr->values[i].string.text);
    
  •     attr->values[i].string.text = NULL;
    
  •     if (attr->values[i].string.charset)
    
  •     {
    
  •   _cupsStrFree(attr->values[i].string.charset);
    
  •   attr->values[i].string.charset = NULL;
    
  •     }
    

- }

  • default :
  •        break;
    

- }

  • /*
    
  •  \* Use the default connection hostname instead...
    

- */

  •  attr->value_tag             = IPP_TAG_NAME;
    
  •  attr->num_values            = 1;
    
  •  attr->values[0].string.text = _cupsStrAlloc(con->http.hostname);
    
  •  ippDeleteAttribute(job->attrs, attr);
    
  •  ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http.hostname);
    

    }

  • attr->group_tag = IPP_TAG_JOB;

  • else

  •  attr->group_tag = IPP_TAG_JOB;
    

    }
    else
    {
    @@ -1445,7 +1411,7 @@

    • the connection...
      */
  • ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,

  • ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
    "job-originating-host-name", NULL, con->http.hostname);
    }

@@ -1559,7 +1525,8 @@
* Force the leading banner to have the classification on it...
*/

  •      cupsdSetString(&attr->values[0].string.text, Classification);
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc(Classification);
    

    cupsdLogMessage(CUPSD_LOG_NOTICE, "[Job %d] CLASSIFICATION FORCED "
    "job-sheets="%s,none", "
    @@ -1576,7 +1543,8 @@

    • Can't put two different security markings on the same document!
      */
  •      cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
    
  • _cupsStrFree(attr->values[1].string.text);
    
  • attr->values[1].string.text = _cupsStrAlloc(attr->values[0].string.text);
    

    cupsdLogMessage(CUPSD_LOG_NOTICE, "[Job %d] CLASSIFICATION FORCED "
    "job-sheets="%s,%s", "
    @@ -1616,18 +1584,26 @@
    if (attr->num_values > 1 &&
    !strcmp(attr->values[0].string.text, attr->values[1].string.text))
    {

  •      cupsdSetString(&(attr->values[0].string.text), Classification);
    
  •      cupsdSetString(&(attr->values[1].string.text), Classification);
    
  • _cupsStrFree(attr->values[0].string.text);
    
  • attr->values[0].string.text = _cupsStrAlloc(Classification);
    
  • _cupsStrFree(attr->values[1].string.text);
    
  • attr->values[1].string.text = _cupsStrAlloc(Classification);
    

    }
    else
    {
    if (attr->num_values == 1 ||
    strcmp(attr->values[0].string.text, "none"))

  •        cupsdSetString(&(attr->values[0].string.text), Classification);
    
  • {
    
  •   _cupsStrFree(attr->values[0].string.text);
    
  •   attr->values[0].string.text = _cupsStrAlloc(Classification);
    
  • }
    
       if (attr->num_values > 1 &&
      strcmp(attr->values[1].string.text, "none"))
    
  •        cupsdSetString(&(attr->values[1].string.text), Classification);
    
  • {
    
  •   _cupsStrFree(attr->values[1].string.text);
    
  •   attr->values[1].string.text = _cupsStrAlloc(Classification);
    
  • }
     }
    
     if (attr->num_values > 1)
    

    @@ -2571,7 +2547,7 @@
    int i, /* Looping var /
    num_options; /
    Number of default options /
    cups_option_t *options, /
    Default options */

  •   _option;        /_ Current option */
    
  •   *option;        /* Current option */
    

    /*
    @@ -2657,7 +2633,7 @@
    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
    sizeof(method), username, sizeof(username), host,

    sizeof(host), &port, resource, sizeof(resource));

    if (strncmp(resource, "/jobs/", 6))
    {
    /*
    @@ -2741,7 +2717,8 @@
    if (attr)
    {
    attr->value_tag = IPP_TAG_KEYWORD;

  • cupsdSetString(&(attr->values[0].string.text), "no-hold");

  • _cupsStrFree(attr->values[0].string.text);

  • attr->values[0].string.text = _cupsStrAlloc("no-hold");
    }

/*
@@ -2971,7 +2948,7 @@
/*
* No, see if there are any pending jobs...

*/

  • for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
    job;
    job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
    @@ -2999,7 +2976,7 @@
    httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
    sizeof(method), username, sizeof(username), host,

sizeof(host), &port, resource, sizeof(resource));

if (strncmp(resource, "/jobs/", 6))
{
/*
@@ -4025,13 +4002,13 @@
if ((!strcmp(system_paper, "Letter") && have_letter) ||
(!strcmp(system_paper, "A4") && have_a4))
{

  •  num_defaults = cupsAddOption("PageSize", system_paper,
    
  •  num_defaults = cupsAddOption("PageSize", system_paper,
               num_defaults, &defaults);
    
  •  num_defaults = cupsAddOption("PageRegion", system_paper,
    
  •  num_defaults = cupsAddOption("PageRegion", system_paper,
               num_defaults, &defaults);
    
  •  num_defaults = cupsAddOption("PaperDimension", system_paper,
    
  •  num_defaults = cupsAddOption("PaperDimension", system_paper,
               num_defaults, &defaults);
    
  •  num_defaults = cupsAddOption("ImageableArea", system_paper,
    
  •  num_defaults = cupsAddOption("ImageableArea", system_paper,
               num_defaults, &defaults);
    

    }
    }
    @@ -4266,7 +4243,7 @@
    if (!ra || cupsArrayFind(ra, "printer-state-change-time"))
    ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,

    "printer-state-change-time", printer->state_time);

    if (MaxPrinterHistory > 0 && printer->num_history > 0 &&
    cupsArrayFind(ra, "printer-state-history"))
    {
    @@ -4467,7 +4444,7 @@
    /*

    • Save and log the job...
      */

      cupsdSaveJob(job);

    cupsdLogMessage(CUPSD_LOG_INFO, "Job %d created on "%s" by "%s".",
    @@ -5053,7 +5030,7 @@
    dest, get_username(con));

    cupsdExpireSubscriptions(printer, NULL);

    /*

    • Remove any old PPD or script files...
      */
      @@ -6348,7 +6325,7 @@
      _("job-printer-uri attribute missing!"));
      return;

      }

      httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, method,
      sizeof(method), username, sizeof(username), host,
      sizeof(host), &port, resource, sizeof(resource));
      @@ -6755,8 +6732,7 @@

      if (format)
      {

- _cupsStrFree(format->values[0].string.text);

  • _cupsStrFree(format->values[0].string.text);
    format->values[0].string.text = _cupsStrAlloc(mimetype);
    }
    else
    @@ -7257,9 +7233,8 @@

if (attr)
{

  • attr->value_tag = IPP_TAG_KEYWORD;
    _cupsStrFree(attr->values[0].string.text);
  • attr->value_tag = IPP_TAG_KEYWORD;
    attr->values[0].string.text = _cupsStrAlloc("no-hold");

cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, job->printer, job,

Index: scheduler/job.c

--- scheduler/job.c (revision 12588)
+++ scheduler/job.c (working copy)
@@ -416,7 +416,10 @@

   if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
                           IPP_TAG_URI)) != NULL)
  •        cupsdSetString(&attr->values[0].string.text, printer->uri);
    
  •      {
    
  •        _cupsStrFree(attr->values[0].string.text);
    
  •        attr->values[0].string.text = _cupsStrAlloc(printer->uri);
    
  •      }
    

    else
    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
    "job-actual-printer-uri", NULL, printer->uri);
    @@ -1197,7 +1200,10 @@

    if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
    IPP_TAG_URI)) != NULL)

  • cupsdSetString(&(attr->values[0].string.text), p->uri);

  • {

  • _cupsStrFree(attr->values[0].string.text);

  • attr->values[0].string.text = _cupsStrAlloc(p->uri);

  • }

cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
"Job #%d moved from %s to %s.", job->id, olddest,
@@ -2429,7 +2435,10 @@
attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
"job-hold-until", NULL, holdstr);
else

  • cupsdSetString(&attr->values[0].string.text, holdstr);
  • {
  • _cupsStrFree(attr->values[0].string.text);
  • attr->values[0].string.text = _cupsStrAlloc(holdstr);
  • }

cupsdSaveJob(job);
}

@michaelrsweet
Copy link
Collaborator Author

"str4609-1.1.patch":

Index: scheduler/ipp.c

--- scheduler/ipp.c (revision 12588)
+++ scheduler/ipp.c (working copy)
@@ -183,7 +183,7 @@
/*

  • Then validate the request header and required attributes...
    */

      if (con->request->request.any.version[0] != 1)
      {
      /*
      @@ -195,7 +195,7 @@
      con->request->request.any.version[1]);

      send_ipp_error(con, IPP_VERSION_NOT_SUPPORTED);

    • }

    • }
      else if (con->request->attrs == NULL)
      {
      LogMessage(L_ERROR, "ProcessIPPRequest: no attributes in request!");
      @@ -1795,7 +1795,7 @@
      */

    httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);

    if (strncmp(resource, "/jobs/", 6) != 0)
    {
    /*
    @@ -2623,13 +2623,13 @@
    strlcpy(system_paper, paper_result, sizeof(system_paper));
    system_paper[0] = toupper(system_paper[0] & 255);

  • num_defaults = ppd_add_default("PageSize", system_paper,

  • num_defaults = ppd_add_default("PageSize", system_paper,
    num_defaults, &defaults);

  • num_defaults = ppd_add_default("PageRegion", system_paper,

  • num_defaults = ppd_add_default("PageRegion", system_paper,
    num_defaults, &defaults);

  • num_defaults = ppd_add_default("PaperDimension", system_paper,

  • num_defaults = ppd_add_default("PaperDimension", system_paper,
    num_defaults, &defaults);

  • num_defaults = ppd_add_default("ImageableArea", system_paper,

  • num_defaults = ppd_add_default("ImageableArea", system_paper,
    num_defaults, &defaults);
    }
    #endif /* HAVE_LIBPAPER */
    @@ -2862,7 +2862,7 @@
    {
    for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++)
    {

  •  if (attr->values[i].range.lower < lowerpagerange || 
    
  •  if (attr->values[i].range.lower < lowerpagerange ||
    

    attr->values[i].range.lower > attr->values[i].range.upper)
    {
    LogMessage(L_ERROR, "create_job: bad page-ranges values %d-%d.",
    @@ -2992,7 +2992,7 @@
    {
    free(attr->values[i].string.text);
    attr->values[i].string.text = NULL;

  •     if (attr->values[i].string.charset)
    
  •     if (!i && attr->values[i].string.charset)
      {
    free(attr->values[i].string.charset);
    attr->values[i].string.charset = NULL;
    

    @@ -3021,7 +3021,7 @@

    • the connection...
      */
  • ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,

  • ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
    "job-originating-host-name", NULL, con->http.hostname);
    }

@@ -3206,7 +3206,7 @@
/*

  • Save and log the job...
    */

    SaveJob(job->id);

    LogMessage(L_INFO, "Job %d created on '%s' by '%s'.", job->id,
    @@ -3641,7 +3641,7 @@
    */

    httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);

    if (strncmp(resource, "/jobs/", 6) != 0)
    {
    /*
    @@ -4088,7 +4088,7 @@
    */

    httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);

    if (strncmp(resource, "/jobs/", 6) != 0)
    {
    /*
    @@ -4228,7 +4228,7 @@
    */

    httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);

    if (strncmp(resource, "/jobs/", 6) != 0)
    {
    /*
    @@ -4296,7 +4296,7 @@
    send_ipp_error(con, IPP_BAD_REQUEST);
    return;

    }

    /*

  • Move the job to a different printer or class...
    */
    @@ -4528,7 +4528,7 @@
    {
    for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++)
    {

    •  if (attr->values[i].range.lower < lowerpagerange || 
      
    •  if (attr->values[i].range.lower < lowerpagerange ||
      
      attr->values[i].range.lower > attr->values[i].range.upper)
      {
      LogMessage(L_ERROR, "print_job: bad page-ranges values %d-%d.",
      @@ -4867,7 +4867,7 @@
      • the connection...
        */
  • ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,

  • ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
    "job-originating-host-name", NULL, con->http.hostname);
    }

@@ -5045,7 +5045,7 @@
}
else if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)

job->sheets = attr;

  • /*
  • Add the job file...
    */
    @@ -5459,7 +5459,7 @@
    */

    httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);

      if (strncmp(resource, "/jobs/", 6) != 0)
      {
      /*
      @@ -5608,7 +5608,7 @@
      */

      httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);

      if (strncmp(resource, "/jobs/", 6) != 0)
      {
      /*
      @@ -5773,7 +5773,7 @@
      */

      httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);

      if (strncmp(resource, "/jobs/", 6) != 0)
      {
      /*
      @@ -6212,7 +6212,7 @@
      */

      httpSeparate(uri->values[0].string.text, method, username, host, &port, resource);

      if (strncmp(resource, "/jobs/", 6) != 0)
      {
      /*

@michaelrsweet
Copy link
Collaborator Author

CUPS.org User: jsmeix.suse

FYI:

Meanwhile the SUSE security team got the following info from CERT

(excerpt):

Furthermore, CVE IDs have been assigned as follows:

* Cross-Site Scripting -- CVE-2015-1159

Perhaps you may like to add the CVEs to change logs and/or
to whatever other places where users may look for them.

@michaelrsweet michaelrsweet added this to the Stable milestone Mar 17, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant