]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
libcupsfilters: Fix resolver functions for DNS-SD-based URIs
authorTill Kamppeter <till.kamppeter@gmail.com>
Thu, 30 Dec 2021 02:12:00 +0000 (23:12 -0300)
committerTill Kamppeter <till.kamppeter@gmail.com>
Thu, 30 Dec 2021 02:12:00 +0000 (23:12 -0300)
CUPS and cups-browsed use DNS-SD-service-name-based URIs, so that the
printer URIs are robust against changes of network details, for
example of the port, if Printer Applications on a system come up in
different order at every boot.

To be able to access the printer these URIs have to get resolved,
which means to get converted into standard IPP URIs. This is done by
two functions with their source being in cupsfilters/ipp.c.

Unfortunately both functions have a bug and in this commit we fix
these bugs to make the functions correctly working in all cases.

1. resolve_uri()

This function calls cupsBackendDeviceURI() of libcups which resolves
device URIs for the CUPS backends. As it is designed for only using in
CUPS backends it needs some workarounds to make it usuable as
universal library function and make it work in a wide range of system
environments.

One workaround was already applied from the beginning on, re-directing
stderr into the Nirwana, to avoid messages to stderr.

Another is needed and now added: We need to unset the DEVICE_URI
environment variable as the function searches for the device URI to
resolve there at first and not as argc[0]. Otherwise, if we are
running under CUPS, in a backend, we get the print queue's device URI
resolved and not the one which we supply.

We save and restore the value of DEVICE_URI to keep the impact as low
as possible.

2. ippfind_based_uri_converter()

In this function the ippfind utility is called in a fork and the
foreground (parent process) is getting ippfind's stdout through a
pipe. The main process is picking up the data to use it for resolving
the given URI. Here the parent process has unnecessarily: "dup"ed the
read end of the pipe to stdin, and then read the lines from
stdin. This prevents the calling program to use stdin by itself, for
example to receive print job data.

Now this is fixed by directly reading from the read end of the pipe.

cupsfilters/ipp.c

index 5078d2a98dda515757fde6a6e5ef54ae1fd94486..3bfcb0a3c322be262973ad2522ead616518e4a90 100644 (file)
@@ -75,6 +75,7 @@ resolve_uri(const char *raw_uri)
   char *pseudo_argv[2];
   const char *uri;
   int fd1, fd2;
+  char *save_device_uri_var;
 
   /* Eliminate any output to stderr, to get rid of the CUPS-backend-specific
      output of the cupsBackendDeviceURI() function */
@@ -83,12 +84,28 @@ resolve_uri(const char *raw_uri)
   dup2(fd2, 2);
   close(fd2);
 
+  /* If set, save the DEVICE_URI environment and then unset it, so that
+     if we are running under CUPS (as filter or backend) our raw_uri gets
+     resolved and not whatever URI is set in DEVICE_URI */
+  if ((save_device_uri_var = getenv("DEVICE_URI")) != NULL)
+  {
+    save_device_uri_var = strdup(save_device_uri_var);
+    unsetenv("DEVICE_URI");
+  }
+
   /* Use the URI resolver of libcups to support DNS-SD-service-name-based
      URIs. The function returns the corresponding host-name-based URI */
   pseudo_argv[0] = (char *)raw_uri;
   pseudo_argv[1] = NULL;
   uri = cupsBackendDeviceURI(pseudo_argv);
 
+  /* Restore DEVICE_URI envidonment variable if we had unset it */
+  if (save_device_uri_var)
+  {
+    setenv("DEVICE_URI", save_device_uri_var, 1);
+    free(save_device_uri_var);
+  }
+
   /* Re-activate stderr output */
   dup2(fd1, 2);
   close(fd1);
@@ -540,11 +557,9 @@ ippfind_based_uri_converter (const char *uri, int is_fax)
     goto error;
   }
 
-  dup2(post_proc_pipe[0], 0);
-  close(post_proc_pipe[0]);
   close(post_proc_pipe[1]);
 
-  fp = cupsFileStdin();
+  fp = cupsFileOpenFd(post_proc_pipe[0], "r");
 
   buffer = (char*)malloc(MAX_OUTPUT_LEN * sizeof(char));
   if (buffer == NULL) {
@@ -604,6 +619,8 @@ ippfind_based_uri_converter (const char *uri, int is_fax)
     memset(buffer, 0, MAX_OUTPUT_LEN);
   }
 
+  cupsFileClose(fp);
+
   if (buffer != NULL)
     free(buffer);