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

libcups does not initialize defaults in some cases #5642

Open
tillkamppeter opened this issue Aug 29, 2019 · 5 comments

Comments

@tillkamppeter
Copy link

commented Aug 29, 2019

I am using CUPS 2.2.12 on Ubuntu Eoan.
Attached is a sample C program testinit.c, to be compiled with

gcc -o testinit testinit.c -lcups

It demonstrates that the internal global data structure cg of libcups in some cases gets used but not initialized.
The program creates a destination record, connects to the CUPS daemon according to the printer URI of the destination and then request the destination info (here CUPS is supposed to do a get-printer-attributes IPP request on the printer URI).
When one calls the program with the name of an existing CUPS printer as argument, for example

./testinit Printer

it should display the IPP attributes of the CUPS queue, but in reality it tells that the queue does not exist. When looking into error_log (in debug mode) one sees that a get-printer-attributes IPP request is done, but to "file:/dev/null" (the device URI in the destination record) and not to the printer URI.
The code of the cupsCopyDestInfo() function contains:

  if (!http)
  {
    DEBUG_puts("1cupsCopyDestInfo: Default server connection.");
    http   = _cupsConnect();
    dflags = CUPS_DEST_FLAGS_NONE;
  }
#ifdef AF_LOCAL
  else if (httpAddrFamily(http->hostaddr) == AF_LOCAL)
  {
    DEBUG_puts("1cupsCopyDestInfo: Connection to server (domain socket).");
    dflags = CUPS_DEST_FLAGS_NONE;
  }
#endif /* AF_LOCAL */
  else if ((strcmp(http->hostname, cg->server) && cg->server[0] != '/') || cg->ipp_port != httpAddrPort(http->hostaddr))
  {
    DEBUG_printf(("1cupsCopyDestInfo: Connection to device (%s).", http->hostname));
    dflags = CUPS_DEST_FLAGS_DEVICE;
  }
  else
  {
    DEBUG_printf(("1cupsCopyDestInfo: Connection to server (%s).", http->hostname));
    dflags = CUPS_DEST_FLAGS_NONE;
  }

What happens here is that the first two "if" conditions resolve to false and the third to true, setting dflags to CUPS_DEST_FLAGS_DEVICE and so the device URI being used for the following get-printer-attributes IPP request and that fails.
The third "if" has the condition

((strcmp(http->hostname, cg->server) && cg->server[0] != '/') || cg->ipp_port != httpAddrPort(http->hostaddr))

If cg->server is "/run/cups/cups.sock" or "localhost" as expected and cg->ipp_port is 631 as expected, this would resolve to false and the last "else" would set dflags to CUPS_DEST_FLAGS_NONE and so the get-printer-attributes IPP request is applied to the CUPS queue.
The only explication that this does not happen is that cg->server contains an arbitrary string and cg->ipp_port and arbitrary number, which makes the condition resolve to true.
If I run my program with an arbitrary second argument, for example

./testinit Printer 1

it calls the function ippPort() in the very beginning before it calls any other function of libcups. The ippPort() function calls the internal function _cupsSetDefaults() of libcups which populates the cg data structure with the defaults.
It needs to get assured that the cg data structure gets always populated.

The sample program:
testinit.c.txt

tillkamppeter added a commit to OpenPrinting/cpdb-backend-cups that referenced this issue Aug 29, 2019
… libcups

The CUPS backend runs into a bug of libcups, of the default server
name, port, domain socket file name not being initialized depending on
which functions of the library are used. See this upstream bug report
on CUPS:

apple/cups#5642

A simple call of "ippPort()" in the very beginning of the backend executable
solves the problem.

This also caused the issue

#2

which is solved now, too.
@michaelrsweet

This comment has been minimized.

Copy link
Collaborator

commented Sep 3, 2019

@tillkamppeter OK, try the same thing but using the cupsGetNamedDest function rather than allocating and initializing the cups_dest_t structure yourself (which BYPASSES all of the normal initializers!)

@michaelrsweet michaelrsweet self-assigned this Sep 3, 2019
@tillkamppeter

This comment has been minimized.

Copy link
Author

commented Sep 3, 2019

The original program (cpdb-backend-cups, version 1.1.0) uses cupsEnumDests() as shown in
testinit-2.c.txt
but uses an event loop and separate threads, the thread separation of the cupsEnumDests() and the later cupsCopyDestInfo() call probably leads to the cupsCopyDestInfo() call on an uninitialized libcups. In my little test program testinit-2 without multi-threading everything works as intended.

@michaelrsweet

This comment has been minimized.

Copy link
Collaborator

commented Sep 12, 2019

OK, so neither test program actually uses threads... Working on a multi-threaded test program now.

@michaelrsweet

This comment has been minimized.

Copy link
Collaborator

commented Oct 2, 2019

Will push the test program soon, but so far I haven't been able to reproduce the problem you are seeing...

michaelrsweet added a commit that referenced this issue Oct 2, 2019
@michaelrsweet

This comment has been minimized.

Copy link
Collaborator

commented Oct 2, 2019

[master cfaaa07] Add threading unit test program (Issue #5642)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.