Submitted By:            Douglas R. Reno <renodr at linuxfromscratch dot org>
Date:                    2024-10-09
Initial Package Version: 2.0.0
Upstream Status:         Applied (commit d6817477e)
Origin:                  Upstream
Description:             Fixes CVE-2024-47175 in libppd. This is part of the
                         exploit chain for an unauthenticated (without user
                         interaction) remote code execution chain in CUPS.
                         This patch fixes the vulnerability by preventing PPD
                         generation based on invalid IPP responses via
                         validating the IPP responses.

diff -Naurp libppd-2.0.0.orig/ppd/ppd-cache.c libppd-2.0.0/ppd/ppd-cache.c
--- libppd-2.0.0.orig/ppd/ppd-cache.c	2024-10-09 14:08:35.791817124 -0500
+++ libppd-2.0.0/ppd/ppd-cache.c	2024-10-09 14:12:53.082328729 -0500
@@ -1,6 +1,7 @@
 //
 // PPD cache implementation for libppd.
 //
+// Copyright © 2024 by OpenPrinting  
 // Copyright © 2010-2019 by Apple Inc.
 //
 // Licensed under Apache License v2.0.  See the file "LICENSE" for more
@@ -3413,7 +3414,7 @@ ppdCacheGetBin(
 
   //
   // Range check input...
- 
+
 
   if (!pc || !output_bin)
     return (NULL);
@@ -3914,7 +3915,7 @@ ppdCacheGetPageSize(
       {
 	//
 	// Check not only the base size (like "A4") but also variants (like
-        // "A4.Borderless"). We check only the margins and orientation but do 
+   // "A4.Borderless"). We check only the margins and orientation but do
 	// not re-check the size.
 	//
 
@@ -4711,7 +4712,7 @@ ppdPwgPpdizeName(const char *ipp,	// I -
 	*end;				// End of name buffer
 
 
-  if (!ipp)
+  if (!ipp || !_ppd_isalnum(*ipp))
   {
     *name = '\0';
     return;
@@ -4721,13 +4722,19 @@ ppdPwgPpdizeName(const char *ipp,	// I -
 
   for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
   {
-    if (*ipp == '-' && _ppd_isalnum(ipp[1]))
+    if (*ipp == '-' && isalnum(ipp[1]))
     {
       ipp ++;
       *ptr++ = (char)toupper(*ipp++ & 255);
     }
+    else if (*ipp == '_' || *ipp == '.' || *ipp == '-' || isalnum(*ipp))
+    {
+       *ptr++ = *ipp++;
+    }
     else
-      *ptr++ = *ipp++;
+    {
+       ipp ++;
+    } 
   }
 
   *ptr = '\0';
diff -Naurp libppd-2.0.0.orig/ppd/ppd-generator.c libppd-2.0.0/ppd/ppd-generator.c
--- libppd-2.0.0.orig/ppd/ppd-generator.c	2024-10-09 14:08:35.791817124 -0500
+++ libppd-2.0.0/ppd/ppd-generator.c	2024-10-09 15:09:46.241654150 -0500
@@ -1,15 +1,16 @@
 //
 //   PWG Raster/Apple Raster/PCLm/PDF/IPP legacy PPD generator for libppd.
 //
-//   Copyright 2016-2019 by Till Kamppeter.
-//   Copyright 2017-2019 by Sahil Arora.
-//   Copyright 2018-2019 by Deepak Patankar.
+//   Copyright © 2024 by OpenPrinting
+//   Copyright © 2016-2019 by Till Kamppeter.
+//   Copyright © 2017-2019 by Sahil Arora.
+//   Copyright © 2018-2019 by Deepak Patankar.
 //
 //   The PPD generator is based on the PPD generator for the CUPS
 //   "lpadmin -m everywhere" functionality in the cups/ppd-cache.c
 //   file. The copyright of this file is:
 //
-//   Copyright 2010-2016 by Apple Inc.
+//   Copyright © 2010-2016 by Apple Inc.
 //
 //   Licensed under Apache License v2.0.  See the file "LICENSE" for more
 //   information.
@@ -51,6 +52,8 @@
 
 static int	http_connect(http_t **http, const char *url, char *resource,
 			     size_t ressize);
+static void ppd_put_string(cups_file_t *fp, cups_lang_t *lang, const char *ppd_option,
+const char *ppd_choice, const char *pwg_msgid);
 
 
 //
@@ -60,7 +63,7 @@ static int	http_connect(http_t **http, c
 // than CUPS 2.2.x. We have also an additional test and development
 // platform for this code. Taken from cups/ppd-cache.c,
 // cups/string-private.h, cups/string.c.
-// 
+//
 // The advantage of PPD generation instead of working with System V
 // interface scripts is that the print dialogs of the clients do not
 // need to ask the printer for its options via IPP. So we have access
@@ -124,7 +127,7 @@ char ppdgenerator_msg[1024];
 //                           IPP 1.x legacy)
 //
 
-char *                                             // O - PPD filename or NULL 
+char *                                             // O - PPD filename or NULL
                                                    //     on error
 ppdCreatePPDFromIPP(char         *buffer,          // I - Filename buffer
 		    size_t       bufsize,          // I - Size of filename
@@ -175,7 +178,7 @@ ppdCreatePPDFromIPP2(char         *buffe
 		     cups_array_t *conflicts,       // I - Array of
 						    //     constraints
 		     cups_array_t *sizes,           // I - Media sizes we've
-						    //     added 
+						    //     added
 		     char*        default_pagesize, // I - Default page size
 		     const char   *default_cluster_color, // I - cluster def
 						    //     color (if cluster's
@@ -188,6 +191,7 @@ ppdCreatePPDFromIPP2(char         *buffe
 						    //     message buffer
 {
   cups_file_t		*fp;		// PPD file
+  cups_lang_t     *lang;   // Localization language
   cups_array_t		*printer_sizes;	// Media sizes we've added
   cups_size_t		*size;		// Current media size
   ipp_attribute_t	*attr,		// xxx-supported
@@ -199,9 +203,10 @@ ppdCreatePPDFromIPP2(char         *buffe
   ipp_t			*media_col,	// Media collection
 			*media_size;	// Media size collection
   char			make[256],	// Make and model
-			*model,		// Model name
+			*mptr,            // Pointer into make and model
 			ppdname[PPD_MAX_NAME];
 		    			// PPD keyword
+  const char *model; // Model name
   int			i, j,		// Looping vars
 			count = 0,	// Number of values
 			bottom,		// Largest bottom margin
@@ -284,6 +289,68 @@ ppdCreatePPDFromIPP2(char         *buffe
   }
 
   //
+  // Get a sanitized make and model...
+  //
+
+  if ((attr = ippFindAttribute(supported, "printer-make-and-model", IPP_TAG_TEXT)) != NULL && ippValidateAttribute(attr))
+  {
+     // Sanitize the model name to only contain PPD-safe characters.
+     strlcpy(make, ippGetString(attr, 0, NULL), sizeof(make));
+
+     for (mptr = make; *mptr; mptr++)
+     {
+        if (*mptr < ' ' || *mptr >= 127 || *mptr == '\"')
+        {
+           // Truncate the make and model on the first bad character...
+           *mptr = '\0';
+           break;
+        }
+     }
+
+     while (mptr > make)
+     {
+        // Strip trailing whitespace...
+        mptr --;
+        if (*mptr == ' ')
+           *mptr = '\0';
+     }
+
+     if (!make[0])
+     {
+        // Use a default make and model if nothing remains...
+        strlcpy(make, "Unknown", sizeof(make));
+     }
+  }
+  else
+  {
+     // Use a default make and model...
+     strlcpy(make, "Unknown", sizeof(make));
+  }
+
+  if (!strncasecmp(make, "Hewlett Packard ", 16) || !strncasecmp(make, "Hewlett-Packard ", 16))
+  {
+     // Normalize HP printer make and model...
+     model = make + 16;
+     strlcpy(make, "HP", sizeof(make));
+
+     if (!strncasecmp(model, "HP ", 3))
+        model += 3;
+  }
+  else if ((mptr = strchr(make, ' ')) != NULL)
+  {
+     // Separate "MAKE MODEL"...
+     while (*mptr && *mptr == ' ')
+        *mptr++ = '\0';
+
+     model = mptr;
+  }
+  else
+  {
+     // No separate model name...
+     model = "Printer";
+  }
+
+  //
   // Standard stuff for PPD file...
   //
 
@@ -311,25 +378,6 @@ ppdCreatePPDFromIPP2(char         *buffe
     }
   }
 
-  if ((attr = ippFindAttribute(supported, "printer-make-and-model",
-			       IPP_TAG_TEXT)) != NULL)
-    strlcpy(make, ippGetString(attr, 0, NULL), sizeof(make));
-  else if (make_model && make_model[0] != '\0')
-    strlcpy(make, make_model, sizeof(make));
-  else
-    strlcpy(make, "Unknown Printer", sizeof(make));
-
-  if (!strncasecmp(make, "Hewlett Packard ", 16) ||
-      !strncasecmp(make, "Hewlett-Packard ", 16))
-  {
-    model = make + 16;
-    strlcpy(make, "HP", sizeof(make));
-  }
-  else if ((model = strchr(make, ' ')) != NULL)
-    *model++ = '\0';
-  else
-    model = make;
-
   cupsFilePrintf(fp, "*Manufacturer: \"%s\"\n", make);
   cupsFilePrintf(fp, "*ModelName: \"%s %s\"\n", make, model);
   cupsFilePrintf(fp, "*Product: \"(%s %s)\"\n", make, model);
@@ -425,21 +473,19 @@ ppdCreatePPDFromIPP2(char         *buffe
   }
   cupsFilePuts(fp, "\"\n");
 
-  if ((attr = ippFindAttribute(supported, "printer-more-info", IPP_TAG_URI)) !=
-      NULL)
+  if ((attr = ippFindAttribute(supported, "printer-more-info", IPP_TAG_URI)) != NULL && ippValidateAttribute(attr))
     cupsFilePrintf(fp, "*APSupplies: \"%s\"\n", ippGetString(attr, 0, NULL));
 
-  if ((attr = ippFindAttribute(supported, "printer-charge-info-uri",
-			       IPP_TAG_URI)) != NULL)
-    cupsFilePrintf(fp, "*cupsChargeInfoURI: \"%s\"\n", ippGetString(attr, 0,
-								    NULL));
+  if ((attr = ippFindAttribute(supported, "printer-charge-info-uri", IPP_TAG_URI)) != NULL && ippValidateAttribute(attr))
+    cupsFilePrintf(fp, "*cupsChargeInfoURI: \"%s\"\n", ippGetString(attr, 0, NULL));
 
   // Message catalogs for UI strings
+  lang = cupsLangDefault();
   opt_strings_catalog = cfCatalogOptionArrayNew();
   cfCatalogLoad(NULL, NULL, opt_strings_catalog);
 
   if ((attr = ippFindAttribute(supported, "printer-strings-uri",
-			       IPP_TAG_URI)) != NULL)
+			       IPP_TAG_URI)) != NULL && ippValidateAttribute(attr))
   {
     printer_opt_strings_catalog = cfCatalogOptionArrayNew();
     cfCatalogLoad(ippGetString(attr, 0, NULL), NULL,
@@ -492,7 +538,7 @@ ppdCreatePPDFromIPP2(char         *buffe
 	  response = cupsDoRequest(http, request, resource);
 
 	  if ((attr = ippFindAttribute(response, "printer-strings-uri",
-				       IPP_TAG_URI)) != NULL)
+				       IPP_TAG_URI)) != NULL && ippValidateAttribute(attr))
 	    cupsFilePrintf(fp, "*cupsStringsURI %s: \"%s\"\n", keyword,
 			   ippGetString(attr, 0, NULL));
 
@@ -518,13 +564,11 @@ ppdCreatePPDFromIPP2(char         *buffe
 				     IPP_TAG_BOOLEAN), 0))
     cupsFilePuts(fp, "*cupsJobAccountingUserId: True\n");
 
-  if ((attr = ippFindAttribute(supported, "printer-privacy-policy-uri",
-			       IPP_TAG_URI)) != NULL)
-    cupsFilePrintf(fp, "*cupsPrivacyURI: \"%s\"\n",
-		   ippGetString(attr, 0, NULL));
+  if ((attr = ippFindAttribute(supported, "printer-privacy-policy-uri", IPP_TAG_URI)) != NULL && ippValidateAttribute(attr))
+    cupsFilePrintf(fp, "*cupsPrivacyURI: \"%s\"\n", ippGetString(attr, 0, NULL));
 
   if ((attr = ippFindAttribute(supported, "printer-mandatory-job-attributes",
-			       IPP_TAG_KEYWORD)) != NULL)
+			       IPP_TAG_KEYWORD)) != NULL && ippValidateAttribute(attr))
   {
     char	prefix = '\"';		// Prefix for string
 
@@ -544,8 +588,7 @@ ppdCreatePPDFromIPP2(char         *buffe
     cupsFilePuts(fp, "\"\n");
   }
 
-  if ((attr = ippFindAttribute(supported, "printer-requested-job-attributes",
-			       IPP_TAG_KEYWORD)) != NULL)
+  if ((attr = ippFindAttribute(supported, "printer-requested-job-attributes", IPP_TAG_KEYWORD)) != NULL&& ippValidateAttribute(attr))
   {
     char	prefix = '\"';		// Prefix for string
 
@@ -664,7 +707,7 @@ ppdCreatePPDFromIPP2(char         *buffe
   }
 
   //
-  // Fax 
+  // Fax
   //
 
   if (is_fax)
@@ -705,21 +748,21 @@ ppdCreatePPDFromIPP2(char         *buffe
 #ifdef CUPS_RASTER_HAVE_APPLERASTER
   else if (cupsArrayFind(pdl_list, "image/urf"))
   {
-    int resStore = 0; // Variable for storing the no. of resolutions in the resolution array 
+    int resStore = 0; // Variable for storing the no. of resolutions in the resolution array
     int resArray[__INT16_MAX__]; // Creating a resolution array supporting a maximum of 32767 resolutions.
     int lowdpi = 0, middpi = 0, hidpi = 0; // Lower , middle and higher resolution
     if ((attr = ippFindAttribute(supported, "urf-supported",
 			IPP_TAG_KEYWORD)) != NULL)
     {
       for (int i = 0, count = ippGetCount(attr); i < count; i ++)
-      {  
+      {
        	const char *rs = ippGetString(attr, i, NULL); // RS values
-        const char *rsCopy = ippGetString(attr, i, NULL); // RS values(copy) 
+        const char *rsCopy = ippGetString(attr, i, NULL); // RS values(copy)
 	if (strncasecmp(rs, "RS", 2)) // Comparing attributes to have RS in
 	                              // the beginning to indicate the
 	                              // resolution feature
 	  continue;
-        int resCount = 0; // Using a count variable which can be reset 
+        int resCount = 0; // Using a count variable which can be reset
         while (*rsCopy != '\0') // Parsing through the copy pointer to
 	                        // determine the no. of resolutions
         {
@@ -817,7 +860,7 @@ ppdCreatePPDFromIPP2(char         *buffe
 	    formatfound = 1;
 	    is_apple = 1;
 	  }
-        } 
+        }
       }
     }
   }
@@ -909,7 +952,7 @@ ppdCreatePPDFromIPP2(char         *buffe
   if (manual_copies == 1)
     cupsFilePuts(fp, "*cupsManualCopies: True\n");
 
-  // No resolution requirements by any of the supported PDLs? 
+  // No resolution requirements by any of the supported PDLs?
   // Use "printer-resolution-supported" attribute
   if (common_res == NULL)
   {
@@ -1027,7 +1070,7 @@ ppdCreatePPDFromIPP2(char         *buffe
   //
   // PageSize/PageRegion/ImageableArea/PaperDimension
   //
- 
+
   cfGenerateSizes(supported, CF_GEN_SIZES_DEFAULT, &printer_sizes, &defattr,
 		  NULL, NULL, NULL, NULL, NULL, NULL,
 		  &min_width, &min_length,
@@ -1406,15 +1449,15 @@ ppdCreatePPDFromIPP2(char         *buffe
         if (!strcmp(sources[j], keyword))
 	  break;
       if (j >= 0)
-	cupsFilePrintf(fp, "*InputSlot %s%s%s: \"<</MediaPosition %d>>setpagedevice\"\n",
-		       ppdname,
-		       (human_readable ? "/" : ""),
-		       (human_readable ? human_readable : ""), j);
+      {
+      	cupsFilePrintf(fp, "*InputSlot %s: \"<</MediaPosition %d>>setpagedevice\"\n", ppdname,j);
+		   ppd_put_string(fp, lang, "InputSlot", ppdname, human_readable);
+      }
       else
-	cupsFilePrintf(fp, "*InputSlot %s%s%s: \"\"\n",
-		       ppdname,
-		       (human_readable ? "/" : ""),
-		       (human_readable ? human_readable : ""));
+      {
+      	cupsFilePrintf(fp, "*InputSlot %s%s%s: \"\"\n", ppdname, human_readable ? "/" : "", human_readable ? human_readable : "");
+		   ppd_put_string(fp, lang, "InputSlot", ppdname, human_readable);
+      }
     }
     cupsFilePuts(fp, "*CloseUI: *InputSlot\n");
   }
@@ -1449,11 +1492,8 @@ ppdCreatePPDFromIPP2(char         *buffe
       human_readable = cfCatalogLookUpChoice((char *)keyword, "media-type",
 					     opt_strings_catalog,
 					     printer_opt_strings_catalog);
-      cupsFilePrintf(fp, "*MediaType %s%s%s: \"<</MediaType(%s)>>setpagedevice\"\n",
-		     ppdname,
-		     (human_readable ? "/" : ""),
-		     (human_readable ? human_readable : ""),
-		     ppdname);
+      cupsFilePrintf(fp, "*MediaType %s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, ppdname);
+      ppd_put_string(fp, lang, "MediaType", ppdname, human_readable);
     }
     cupsFilePuts(fp, "*CloseUI: *MediaType\n");
   }
@@ -1776,10 +1816,8 @@ ppdCreatePPDFromIPP2(char         *buffe
       human_readable = cfCatalogLookUpChoice((char *)keyword, "output-bin",
 					     opt_strings_catalog,
 					     printer_opt_strings_catalog);
-      cupsFilePrintf(fp, "*OutputBin %s%s%s: \"\"\n",
-		     ppdname,
-		     (human_readable ? "/" : ""),
-		     (human_readable ? human_readable : ""));
+      cupsFilePrintf(fp, "*OutputBin %s: \"\"\n", ppdname);
+      ppd_put_string(fp, lang, "OutputBin", ppdname, human_readable);
       outputorderinfofound = 0;
       faceupdown = 1;
       firsttolast = 1;
@@ -1833,7 +1871,7 @@ ppdCreatePPDFromIPP2(char         *buffe
 
   //
   // Finishing options...
-  // 
+  //
 
   if ((attr = ippFindAttribute(supported, "finishings-supported",
 			       IPP_TAG_ENUM)) != NULL)
@@ -1958,9 +1996,8 @@ ppdCreatePPDFromIPP2(char         *buffe
 	human_readable = cfCatalogLookUpChoice(buf, "finishings",
 					       opt_strings_catalog,
 					       printer_opt_strings_catalog);
-	cupsFilePrintf(fp, "*StapleLocation %s%s%s: \"\"\n", ppd_keyword,
-		       (human_readable ? "/" : ""),
-		       (human_readable ? human_readable : ""));
+	cupsFilePrintf(fp, "*StapleLocation %s: \"\"\n", ppd_keyword);
+   ppd_put_string(fp, lang, "StapleLocation", ppd_keyword, human_readable);
 	cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n",
 		       value, keyword, ppd_keyword);
       }
@@ -2050,9 +2087,8 @@ ppdCreatePPDFromIPP2(char         *buffe
 	human_readable = cfCatalogLookUpChoice(buf, "finishings",
 					       opt_strings_catalog,
 					       printer_opt_strings_catalog);
-	cupsFilePrintf(fp, "*FoldType %s%s%s: \"\"\n", ppd_keyword,
-		       (human_readable ? "/" : ""),
-		       (human_readable ? human_readable : ""));
+	cupsFilePrintf(fp, "*FoldType %s: \"\"\n", ppd_keyword);
+   ppd_put_string(fp, lang, "FoldType", ppd_keyword, human_readable);
 	cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n",
 		       value, keyword, ppd_keyword);
       }
@@ -2149,9 +2185,8 @@ ppdCreatePPDFromIPP2(char         *buffe
 	human_readable = cfCatalogLookUpChoice(buf, "finishings",
 					       opt_strings_catalog,
 					       printer_opt_strings_catalog);
-	cupsFilePrintf(fp, "*PunchMedia %s%s%s: \"\"\n", ppd_keyword,
-		       (human_readable ? "/" : ""),
-		       (human_readable ? human_readable : ""));
+	cupsFilePrintf(fp, "*PunchMedia %s: \"\"\n", ppd_keyword);
+   ppd_put_string(fp, lang, "PunchMedia", ppd_keyword, human_readable);
 	cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n",
 		       value, keyword, ppd_keyword);
       }
@@ -2242,9 +2277,8 @@ ppdCreatePPDFromIPP2(char         *buffe
 	human_readable = cfCatalogLookUpChoice(buf, "finishings",
 					       opt_strings_catalog,
 					       printer_opt_strings_catalog);
-	cupsFilePrintf(fp, "*CutMedia %s%s%s: \"\"\n", ppd_keyword,
-		       (human_readable ? "/" : ""),
-		       (human_readable ? human_readable : ""));
+	cupsFilePrintf(fp, "*CutMedia %s: \"\"\n", ppd_keyword);
+   ppd_put_string(fp, lang, "CutMedia", ppd_keyword, human_readable);
 	cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*CutMedia %s\"\n",
 		       value, keyword, ppd_keyword);
       }
@@ -2268,7 +2302,7 @@ ppdCreatePPDFromIPP2(char         *buffe
     cupsFilePrintf(fp, "*OpenUI *cupsFinishingTemplate/%s: PickOne\n",
 		   (human_readable ? human_readable : "Finishing Template"));
     cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n");
-    cupsFilePuts(fp, "*DefaultcupsFinishingTemplate: none\n");
+    cupsFilePuts(fp, "*DefaultcupsFinishingTemplate: None\n");
     human_readable = cfCatalogLookUpChoice("3", "finishings",
 					   opt_strings_catalog,
 					   printer_opt_strings_catalog);
@@ -2299,8 +2333,9 @@ ppdCreatePPDFromIPP2(char         *buffe
 					     printer_opt_strings_catalog);
       if (human_readable == NULL)
 	human_readable = (char *)keyword;
-      cupsFilePrintf(fp, "*cupsFinishingTemplate %s/%s: \"\n", keyword,
-		     human_readable);
+      ppdPwgPpdizeName(keyword, ppdname, sizeof(ppdname));
+      cupsFilePrintf(fp, "*cupsFinishingTemplate %s: \"\n", ppdname);
+      ppd_put_string(fp, lang, "cupsFinishingTemplate", ppdname, human_readable);
       for (finishing_attr = ippFirstAttribute(finishing_col); finishing_attr;
 	   finishing_attr = ippNextAttribute(finishing_col)) {
         if (ippGetValueTag(finishing_attr) == IPP_TAG_BEGIN_COLLECTION) {
@@ -2564,14 +2599,13 @@ ppdCreatePPDFromIPP2(char         *buffe
       if (!preset || !preset_name)
         continue;
 
-      if ((localized_name =
-	   cfCatalogLookUpOption((char *)preset_name,
-				 opt_strings_catalog,
-				 printer_opt_strings_catalog)) == NULL)
-        cupsFilePrintf(fp, "*APPrinterPreset %s: \"\n", preset_name);
-      else
-        cupsFilePrintf(fp, "*APPrinterPreset %s/%s: \"\n", preset_name,
-		       localized_name);
+      ppdPwgPpdizeName(preset_name, ppdname, sizeof(ppdname));
+      localized_name =
+  	     cfCatalogLookUpOption((char *)preset_name,
+ 				                  opt_strings_catalog,
+				                  printer_opt_strings_catalog);
+        cupsFilePrintf(fp, "*APPrinterPreset %s: \"\n", ppdname);
+        ppd_put_string(fp, lang, "APPrinterPreset", ppdname, localized_name);
 
       for (member = ippFirstAttribute(preset); member;
 	   member = ippNextAttribute(preset))
@@ -2620,7 +2654,10 @@ ppdCreatePPDFromIPP2(char         *buffe
 		 ippGetString(ippFindAttribute(fin_col,
 					       "finishing-template",
 					       IPP_TAG_ZERO), 0, NULL)) != NULL)
-              cupsFilePrintf(fp, "*cupsFinishingTemplate %s\n", keyword);
+            {
+               ppdPwgPpdizeName(keyword, ppdname, sizeof(ppdname));
+               cupsFilePrintf(fp, "*cupsFinishingTemplate %s\n", ppdname);
+            }
           }
         }
 	else if (!strcmp(member_name, "media"))
@@ -2659,7 +2696,7 @@ ppdCreatePPDFromIPP2(char         *buffe
 				      NULL)) != NULL)
 	  {
             ppdPwgPpdizeName(keyword, ppdname, sizeof(ppdname));
-            cupsFilePrintf(fp, "*InputSlot %s\n", keyword);
+            cupsFilePrintf(fp, "*InputSlot %s\n", ppdname);
 	  }
 
           if ((keyword = ippGetString(ippFindAttribute(media_col, "media-type",
@@ -2667,7 +2704,7 @@ ppdCreatePPDFromIPP2(char         *buffe
 				      NULL)) != NULL)
 	  {
             ppdPwgPpdizeName(keyword, ppdname, sizeof(ppdname));
-            cupsFilePrintf(fp, "*MediaType %s\n", keyword);
+            cupsFilePrintf(fp, "*MediaType %s\n", ppdname);
 	  }
         }
 	else if (!strcmp(member_name, "print-quality"))
@@ -2817,3 +2854,37 @@ http_connect(http_t     **http,		// IO -
 
   return (*http != NULL);
 }
+
+/*
+ * 'ppd_put_strings()' - Write localization attributes to a PPD file.
+ */
+
+static void
+ppd_put_string(cups_file_t *fp,        /* I - PPD file */
+               cups_lang_t *lang,      /* I - Language */
+               const char  *ppd_option,/* I - PPD option */
+               const char  *ppd_choice,/* I - PPD choice*/
+               const char  *text)      /* I - Localized text */
+{
+   if (!text)
+      return;
+
+   // Add the first line of localized text...
+#if CUPS_VERSION_MAJOR > 2
+   cupsFilePrintf(fp, "*%s.%s %s/", cupsLangGetName(lang), ppd_option, ppd_choice);
+#else
+   cupsFilePrintf(fp, "*%s.%s %s/", lang->language, ppd_option, ppd_choice);
+#endif // CUPS_VERSION_MAJOR >2
+
+   while (*text && *text != '\n')
+   {
+      // Escape ":" and "<"...
+      if (*text == ':' || *text == '<')
+         cupsFilePrintf(fp, "<%02X>", *text);
+      else
+         cupsFilePutChar(fp, *text);
+
+      text ++;
+   }
+   cupsFilePuts(fp, ": \"\"\n");
+}
