]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - systemv/lpoptions.c
Sandboxed applications were not able to get the default printer (Issue #5676)
[thirdparty/cups.git] / systemv / lpoptions.c
index 5cef4a97936bffcc48687cbc10f1d3a77c0d6879..08746c000cf70c8e3223411aecb93580668a2cc0 100644 (file)
@@ -1,34 +1,19 @@
 /*
- * "$Id: lpoptions.c 7720 2008-07-11 22:46:21Z mike $"
+ * Printer option program for CUPS.
  *
- *   Printer option program for the Common UNIX Printing System (CUPS).
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2006 by Easy Software Products.
  *
- *   Copyright 2007-2009 by Apple Inc.
- *   Copyright 1997-2006 by Easy Software Products.
- *
- *   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://www.cups.org/".
- *
- * Contents:
- *
- *   main()         - Main entry.
- *   list_group()   - List printer-specific options from the PPD group.
- *   list_options() - List printer-specific options from the PPD file.
- *   usage()        - Show program usage and exit.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
  */
 
 /*
  * Include necessary headers...
  */
 
-#include <cups/string.h>
-#include <cups/cups.h>
-#include <cups/i18n.h>
-#include <stdlib.h>
-#include <errno.h>
+#include <cups/cups-private.h>
+#include <cups/ppd-private.h>
 
 
 /*
@@ -37,7 +22,7 @@
 
 static void    list_group(ppd_file_t *ppd, ppd_group_t *group);
 static void    list_options(cups_dest_t *dest);
-static void    usage(void);
+static void    usage(void) _CUPS_NORETURN;
 
 
 /*
@@ -55,8 +40,9 @@ main(int  argc,                               /* I - Number of command-line arguments */
   int          num_dests;              /* Number of destinations */
   cups_dest_t  *dests;                 /* Destinations */
   cups_dest_t  *dest;                  /* Current destination */
-  char         *printer,               /* Printer name */
-               *instance,              /* Instance name */ 
+  char         *opt,                   /* Option pointer */
+               *printer,               /* Printer name */
+               *instance,              /* Instance name */
                *option;                /* Current option */
 
 
@@ -74,271 +60,258 @@ main(int  argc,                           /* I - Number of command-line arguments */
   changes     = 0;
 
   for (i = 1; i < argc; i ++)
-    if (argv[i][0] == '-')
+  {
+    if (!strcmp(argv[i], "--help"))
+      usage();
+    else if (argv[i][0] == '-')
     {
-      switch (argv[i][1])
+      for (opt = argv[i] + 1; *opt; opt ++)
       {
-        case 'd' : /* -d printer */
-           if (argv[i][2])
-             printer = argv[i] + 2;
-           else
-           {
-             i ++;
-             if (i >= argc)
-               usage();
-
-             printer = argv[i];
-           }
-
-            if ((instance = strrchr(printer, '/')) != NULL)
-             *instance++ = '\0';
-
-           if (num_dests == 0)
-             num_dests = cupsGetDests(&dests);
-
-            if (num_dests == 0 || !dests ||
-               (dest = cupsGetDest(printer, instance, num_dests,
-                                   dests)) == NULL)
-           {
-             _cupsLangPuts(stderr,
-                           _("lpoptions: Unknown printer or class\n"));
-             return (1);
-           }
-
-          /*
-           * Set the default destination...
-           */
-
-           for (j = 0; j < num_dests; j ++)
-             dests[j].is_default = 0;
-
-           dest->is_default = 1;
-
-           cupsSetDests(num_dests, dests);
-
-           for (j = 0; j < dest->num_options; j ++)
-             if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
-               num_options = cupsAddOption(dest->options[j].name,
-                                           dest->options[j].value,
-                                           num_options, &options);
-           break;
-
-       case 'h' : /* -h server */
-           if (argv[i][2])
-             cupsSetServer(argv[i] + 2);
-           else
-           {
-             i ++;
-             if (i >= argc)
-               usage();
+       switch (*opt)
+       {
+         case 'd' : /* -d printer */
+             if (opt[1] != '\0')
+             {
+               printer = opt + 1;
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+               if (i >= argc)
+                 usage();
 
-             cupsSetServer(argv[i]);
-           }
-           break;
+               printer = argv[i];
+             }
 
-        case 'E' : /* Encrypt connection */
-           cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
-           break;
+             if ((instance = strrchr(printer, '/')) != NULL)
+               *instance++ = '\0';
 
-       case 'l' : /* -l (list options) */
-            if (dest == NULL)
-           {
              if (num_dests == 0)
                num_dests = cupsGetDests(&dests);
 
-             if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
-               dest = dests;
-           }
-
-            if (dest == NULL)
-             _cupsLangPuts(stderr, _("lpoptions: No printers\n"));
-           else
-             list_options(dest);
+             if (num_dests == 0 || !dests || (dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
+             {
+               _cupsLangPuts(stderr, _("lpoptions: Unknown printer or class."));
+               return (1);
+             }
 
-            changes = -1;
-           break;
+            /*
+             * Set the default destination...
+             */
 
-       case 'o' : /* -o option[=value] */
-            if (dest == NULL)
-           {
-             if (num_dests == 0)
-               num_dests = cupsGetDests(&dests);
+             for (j = 0; j < num_dests; j ++)
+               dests[j].is_default = 0;
 
-             if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
-               dest = dests;
+             dest->is_default = 1;
 
-             if (dest == NULL)
-              {
-               _cupsLangPuts(stderr, _("lpoptions: No printers\n"));
-                return (1);
-              }
+             cupsSetDests(num_dests, dests);
 
              for (j = 0; j < dest->num_options; j ++)
-               if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
+               if (cupsGetOption(dest->options[j].name, num_options,
+                                 options) == NULL)
                  num_options = cupsAddOption(dest->options[j].name,
-                                             dest->options[j].value,
-                                             num_options, &options);
-           }
+                                             dest->options[j].value,
+                                             num_options, &options);
+             break;
 
-           if (argv[i][2])
-             num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
-           else
-           {
-             i ++;
-             if (i >= argc)
-               usage();
+         case 'h' : /* -h server */
+             if (opt[1] != '\0')
+             {
+               cupsSetServer(opt + 1);
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+               if (i >= argc)
+                 usage();
 
-             num_options = cupsParseOptions(argv[i], num_options, &options);
-           }
+               cupsSetServer(argv[i]);
+             }
+             break;
 
-           changes = 1;
-           break;
+         case 'E' : /* Encrypt connection */
+             cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+             break;
 
-       case 'p' : /* -p printer */
-           if (argv[i][2])
-             printer = argv[i] + 2;
-           else
-           {
-             i ++;
-             if (i >= argc)
-               usage();
+         case 'l' : /* -l (list options) */
+             if (dest == NULL)
+             {
+               if (num_dests == 0)
+                 num_dests = cupsGetDests(&dests);
 
-             printer = argv[i];
-           }
+               if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
+                 dest = dests;
+             }
 
-            if ((instance = strrchr(printer, '/')) != NULL)
-             *instance++ = '\0';
+             if (dest == NULL)
+               _cupsLangPuts(stderr, _("lpoptions: No printers."));
+             else
+               list_options(dest);
 
-           if (num_dests == 0)
-             num_dests = cupsGetDests(&dests);
+             changes = -1;
+             break;
 
-            if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
-           {
-             num_dests = cupsAddDest(printer, instance, num_dests, &dests);
-             dest      = cupsGetDest(printer, instance, num_dests, dests);
+         case 'o' : /* -o option[=value] */
+             if (dest == NULL)
+             {
+               if (num_dests == 0)
+                 num_dests = cupsGetDests(&dests);
+
+               if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
+                 dest = dests;
+
+               if (dest == NULL)
+               {
+                 _cupsLangPuts(stderr, _("lpoptions: No printers."));
+                 return (1);
+               }
+
+               for (j = 0; j < dest->num_options; j ++)
+                 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
+                   num_options = cupsAddOption(dest->options[j].name,
+                                               dest->options[j].value,
+                                               num_options, &options);
+             }
 
-              if (dest == NULL)
+             if (opt[1] != '\0')
              {
-               _cupsLangPrintf(stderr,
-                               _("lpoptions: Unable to add printer or "
-                                 "instance: %s\n"),
-                               strerror(errno));
-               return (1);
+               num_options = cupsParseOptions(opt + 1, num_options, &options);
+               opt += strlen(opt) - 1;
              }
-           }
+             else
+             {
+               i ++;
+               if (i >= argc)
+                 usage();
 
-           for (j = 0; j < dest->num_options; j ++)
-             if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
-               num_options = cupsAddOption(dest->options[j].name,
-                                           dest->options[j].value,
-                                           num_options, &options);
-           break;
+               num_options = cupsParseOptions(argv[i], num_options, &options);
+             }
+
+             changes = 1;
+             break;
+
+         case 'p' : /* -p printer */
+             if (opt[1] != '\0')
+             {
+               printer = opt + 1;
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+               if (i >= argc)
+                 usage();
+
+               printer = argv[i];
+             }
+
+             if ((instance = strrchr(printer, '/')) != NULL)
+               *instance++ = '\0';
 
-       case 'r' : /* -r option (remove) */
-            if (dest == NULL)
-           {
              if (num_dests == 0)
                num_dests = cupsGetDests(&dests);
 
-             if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
-               dest = dests;
-
-             if (dest == NULL)
-              {
-               _cupsLangPuts(stderr, _("lpoptions: No printers\n"));
-                return (1);
-              }
+             if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
+             {
+               num_dests = cupsAddDest(printer, instance, num_dests, &dests);
+               dest      = cupsGetDest(printer, instance, num_dests, dests);
+
+               if (dest == NULL)
+               {
+                 _cupsLangPrintf(stderr, _("lpoptions: Unable to add printer or instance: %s"), strerror(errno));
+                 return (1);
+               }
+             }
 
              for (j = 0; j < dest->num_options; j ++)
                if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
                  num_options = cupsAddOption(dest->options[j].name,
-                                             dest->options[j].value,
-                                             num_options, &options);
-           }
+                                             dest->options[j].value,
+                                             num_options, &options);
+             break;
 
-           if (argv[i][2])
-             option = argv[i] + 2;
-           else
-           {
-             i ++;
-             if (i >= argc)
-               usage();
-
-             option = argv[i];
-           }
-
-            for (j = 0; j < num_options; j ++)
-             if (!strcasecmp(options[j].name, option))
+         case 'r' : /* -r option (remove) */
+             if (dest == NULL)
              {
-              /*
-               * Remove this option...
-               */
-
-               num_options --;
-
-               if (j < num_options)
-                 memcpy(options + j, options + j + 1,
-                        sizeof(cups_option_t) * (num_options - j));
-               break;
-              }
-
-           changes = 1;
-           break;
-
-        case 'x' : /* -x printer */
-           if (argv[i][2])
-             printer = argv[i] + 2;
-           else
-           {
-             i ++;
-             if (i >= argc)
-               usage();
-
-             printer = argv[i];
-           }
+               if (num_dests == 0)
+                 num_dests = cupsGetDests(&dests);
+
+               if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
+                 dest = dests;
+
+               if (dest == NULL)
+               {
+                 _cupsLangPuts(stderr, _("lpoptions: No printers."));
+                 return (1);
+               }
+
+               for (j = 0; j < dest->num_options; j ++)
+                 if (cupsGetOption(dest->options[j].name, num_options,
+                                   options) == NULL)
+                   num_options = cupsAddOption(dest->options[j].name,
+                                               dest->options[j].value,
+                                               num_options, &options);
+             }
 
-            if ((instance = strrchr(printer, '/')) != NULL)
-             *instance++ = '\0';
+             if (opt[1] != '\0')
+             {
+               option = opt + 1;
+               opt += strlen(opt) - 1;
+             }
+             else
+             {
+               i ++;
+               if (i >= argc)
+                 usage();
 
-           if (num_dests == 0)
-             num_dests = cupsGetDests(&dests);
+               option = argv[i];
+             }
 
-            if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL)
-           {
-              cupsFreeOptions(dest->num_options, dest->options);
+              num_options = cupsRemoveOption(option, num_options, &options);
 
-             /*
-             * If we are "deleting" the default printer, then just set the
-             * number of options to 0; if it is also the system default
-             * then cupsSetDests() will remove it for us...
-             */
+             changes = 1;
+             break;
 
-             if (dest->is_default)
+         case 'x' : /* -x printer */
+             if (opt[1] != '\0')
              {
-               dest->num_options = 0;
-               dest->options     = NULL;
+               printer = opt + 1;
+               opt += strlen(opt) - 1;
              }
              else
              {
-               num_dests --;
+               i ++;
+               if (i >= argc)
+                 usage();
 
-               j = dest - dests;
-               if (j < num_dests)
-                 memcpy(dest, dest + 1, (num_dests - j) * sizeof(cups_dest_t));
+               printer = argv[i];
              }
-           }
 
-           cupsSetDests(num_dests, dests);
-           dest    = NULL;
-           changes = -1;
-           break;
+             if ((instance = strrchr(printer, '/')) != NULL)
+               *instance++ = '\0';
+
+             if (num_dests == 0)
+               num_dests = cupsGetDests(&dests);
+
+              num_dests = cupsRemoveDest(printer, instance, num_dests, &dests);
+
+             cupsSetDests(num_dests, dests);
+             dest    = NULL;
+             changes = -1;
+             break;
 
-       default :
-           usage();
+         default :
+             usage();
+       }
       }
     }
     else
+    {
       usage();
+    }
+  }
 
   if (num_dests == 0)
     num_dests = cupsGetDests(&dests);
@@ -373,26 +346,31 @@ main(int  argc,                           /* I - Number of command-line arguments */
   }
   else if (changes == 0)
   {
+    char       buffer[10240],          /* String for options */
+               *ptr;                   /* Pointer into string */
+
     num_options = dest->num_options;
     options     = dest->options;
 
-    for (i = 0; i < num_options; i ++)
+    for (i = 0, ptr = buffer;
+         ptr < (buffer + sizeof(buffer) - 1) && i < num_options;
+        i ++)
     {
       if (i)
-        _cupsLangPuts(stdout, " ");
+        *ptr++ = ' ';
 
       if (!options[i].value[0])
-        _cupsLangPrintf(stdout, "%s", options[i].name);
+        strlcpy(ptr, options[i].name, sizeof(buffer) - (size_t)(ptr - buffer));
       else if (strchr(options[i].value, ' ') != NULL ||
                strchr(options[i].value, '\t') != NULL)
-       _cupsLangPrintf(stdout, "%s=\'%s\'", options[i].name,
-                       options[i].value);
+       snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=\'%s\'", options[i].name, options[i].value);
       else
-       _cupsLangPrintf(stdout, "%s=%s", options[i].name,
-                       options[i].value);
+       snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=%s", options[i].name, options[i].value);
+
+      ptr += strlen(ptr);
     }
 
-    _cupsLangPuts(stdout, "\n");
+    _cupsLangPuts(stdout, buffer);
   }
 
   return (0);
@@ -410,19 +388,23 @@ list_group(ppd_file_t  *ppd,              /* I - PPD file */
   ppd_option_t *option;                /* Current option */
   ppd_choice_t *choice;                /* Current choice */
   ppd_group_t  *subgroup;              /* Current subgroup */
+  char         buffer[10240],          /* Option string buffer */
+               *ptr;                   /* Pointer into option string */
 
 
   for (i = group->num_options, option = group->options; i > 0; i --, option ++)
   {
-    if (!strcasecmp(option->keyword, "PageRegion"))
+    if (!_cups_strcasecmp(option->keyword, "PageRegion"))
       continue;
 
-    _cupsLangPrintf(stdout, "%s/%s:", option->keyword, option->text);
+    snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text);
 
-    for (j = option->num_choices, choice = option->choices;
-         j > 0;
+    for (j = option->num_choices, choice = option->choices,
+             ptr = buffer + strlen(buffer);
+         j > 0 && ptr < (buffer + sizeof(buffer) - 1);
         j --, choice ++)
-      if (!strcasecmp(choice->choice, "Custom"))
+    {
+      if (!_cups_strcasecmp(choice->choice, "Custom"))
       {
         ppd_coption_t  *coption;       /* Custom option */
         ppd_cparam_t   *cparam;        /* Custom parameter */
@@ -441,18 +423,16 @@ list_group(ppd_file_t  *ppd,              /* I - PPD file */
 
         if ((coption = ppdFindCustomOption(ppd, option->keyword)) == NULL ||
            cupsArrayCount(coption->params) == 0)
-         _cupsLangPrintf(stdout, " %sCustom", choice->marked ? "*" : "");
-        else if (!strcasecmp(option->keyword, "PageSize") ||
-               !strcasecmp(option->keyword, "PageRegion"))
-         _cupsLangPrintf(stdout, " %sCustom.WIDTHxHEIGHT",
-                         choice->marked ? "*" : "");
+         snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom", choice->marked ? "*" : "");
+        else if (!_cups_strcasecmp(option->keyword, "PageSize") ||
+                !_cups_strcasecmp(option->keyword, "PageRegion"))
+         snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : "");
         else
        {
          cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
 
          if (cupsArrayCount(coption->params) == 1)
-           _cupsLangPrintf(stdout, " %sCustom.%s", choice->marked ? "*" : "",
-                           types[cparam->type]);
+           snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.%s", choice->marked ? "*" : "", types[cparam->type]);
          else
          {
            const char  *prefix;        /* Prefix string */
@@ -465,22 +445,26 @@ list_group(ppd_file_t  *ppd,              /* I - PPD file */
 
            while (cparam)
            {
-             _cupsLangPrintf(stdout, "%s%s=%s", prefix, cparam->name,
-                             types[cparam->type]);
+             snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s%s=%s", prefix, cparam->name, types[cparam->type]);
              cparam = (ppd_cparam_t *)cupsArrayNext(coption->params);
              prefix = " ";
+             ptr += strlen(ptr);
            }
 
-           _cupsLangPuts(stdout, "}");
+            if (ptr < (buffer + sizeof(buffer) - 1))
+             strlcpy(ptr, "}", sizeof(buffer) - (size_t)(ptr - buffer));
          }
        }
       }
       else if (choice->marked)
-        _cupsLangPrintf(stdout, " *%s", choice->choice);
+        snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " *%s", choice->choice);
       else
-        _cupsLangPrintf(stdout, " %s", choice->choice);
+        snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %s", choice->choice);
+
+      ptr += strlen(ptr);
+    }
 
-    _cupsLangPuts(stdout, "\n");
+    _cupsLangPuts(stdout, buffer);
   }
 
   for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
@@ -495,25 +479,36 @@ list_group(ppd_file_t  *ppd,              /* I - PPD file */
 static void
 list_options(cups_dest_t *dest)                /* I - Destination to list */
 {
+  http_t       *http;                  /* Connection to destination */
+  char         resource[1024];         /* Resource path */
   int          i;                      /* Looping var */
   const char   *filename;              /* PPD filename */
   ppd_file_t   *ppd;                   /* PPD data */
   ppd_group_t  *group;                 /* Current group */
 
 
-  if ((filename = cupsGetPPD(dest->name)) == NULL)
+  if ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, resource, sizeof(resource), NULL, NULL)) == NULL)
+  {
+    _cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"),
+                   dest->name, cupsLastErrorString());
+    return;
+  }
+
+  if ((filename = cupsGetPPD2(http, dest->name)) == NULL)
   {
-    _cupsLangPrintf(stderr,
-                    _("lpoptions: Unable to get PPD file for %s: %s\n"),
+    httpClose(http);
+
+    _cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"),
                    dest->name, cupsLastErrorString());
     return;
   }
 
+  httpClose(http);
+
   if ((ppd = ppdOpenFile(filename)) == NULL)
   {
     unlink(filename);
-    _cupsLangPrintf(stderr,
-                    _("lpoptions: Unable to open PPD file for %s\n"),
+    _cupsLangPrintf(stderr, _("lpoptions: Unable to open PPD file for %s."),
                    dest->name);
     return;
   }
@@ -536,17 +531,19 @@ list_options(cups_dest_t *dest)           /* I - Destination to list */
 static void
 usage(void)
 {
-  _cupsLangPuts(stdout,
-                _("Usage: lpoptions [-h server] [-E] -d printer\n"
-                 "       lpoptions [-h server] [-E] [-p printer] -l\n"
-                 "       lpoptions [-h server] [-E] -p printer -o "
-                 "option[=value] ...\n"
-                 "       lpoptions [-h server] [-E] -x printer\n"));
+  _cupsLangPuts(stdout, _("Usage: lpoptions [options] -d destination\n"
+                          "       lpoptions [options] [-p destination] [-l]\n"
+                          "       lpoptions [options] [-p destination] -o option[=value]\n"
+                          "       lpoptions [options] -x destination"));
+  _cupsLangPuts(stdout, _("Options:"));
+  _cupsLangPuts(stdout, _("-d destination          Set default destination"));
+  _cupsLangPuts(stdout, _("-E                      Encrypt the connection to the server"));
+  _cupsLangPuts(stdout, _("-h server[:port]        Connect to the named server and port"));
+  _cupsLangPuts(stdout, _("-l                      Show supported options and values"));
+  _cupsLangPuts(stdout, _("-o name[=value]         Set default option and value"));
+  _cupsLangPuts(stdout, _("-p destination          Specify a destination"));
+  _cupsLangPuts(stdout, _("-U username             Specify the username to use for authentication"));
+  _cupsLangPuts(stdout, _("-x destination          Remove default options for destination"));
 
   exit(1);
 }
-
-
-/*
- * End of "$Id: lpoptions.c 7720 2008-07-11 22:46:21Z mike $".
- */