Subject: [alpine-devel] no cups driver in ghostscript

From: Isaac Dunham <[email-masked]>
Date: Sun, 29 Jun 2014 12:48:34 -0700

I've been trying to get cups working with a Brother DCP-7065-DN.
I still haven't figured out how to get the binary driver going with
musl and grsec (though adding eglibc might work...).
But Peter de Wacht mentioned a driver that might work with it (brlaser,
github.com/pdewacht/brlaser), so I thought I'd try testing it.

I've run into several cases of missing dependencies: cups needs cups-filters,
a2ps (I think), ghostscript, and ghostscript-fonts. But I ran into another
problem:

D [29/Jun/2014:08:31:13 +0700] [Job 8] Ghostscript command line:
/usr/bin/gs -dQUIET -dPARANOIDSAFER -dNOPAUSE -dBATCH -dNOINTERPOLATE
-sDEVICE=cups -sstdout=%stderr -sOutputFile=%stdout -sMediaType=PLAIN
-r600x600 -dDEVICEWIDTHPOINTS=612 -dDEVICEHEIGHTPOINTS=792
-dcupsBitsPerColor=1 -dcupsColorOrder=0 -dcupsColorSpace=3 
-scupsPageSizeName=Letter -I/usr/share/cups/fonts 
-c '<</.HWMargins[8.000000 8.000000 8.000000 16.000000] 
/Margins[0 0]>>setpagedevice' -f -_
...
D [29/Jun/2014:08:31:13 +0700] [Job 8] Unknown device: cups

Any idea what the issue is here?  I can provide the full logs if needed.

Thanks,
Isaac Dunham

---
Unsubscribe:  [email-masked]
Help:         [email-masked]
---

---

From: Isaac Dunham <[email-masked]>
Date: Sun, 29 Jun 2014 17:12:02 -0700

> I've been trying to get cups working with a Brother DCP-7065-DN.
<snip> 
> D [29/Jun/2014:08:31:13 +0700] [Job 8] Unknown device: cups

And the answer to this is to
-add cups-dev to makedepends
-change '--with-drivers=FILES' to '--with-drivers=FILES,cups'

In addition to this, to get a working cups you need to install:
cups cups-filters a2ps ghostscript-fonts ghostscript #the new cups ghostscript
and install a driver.

In my case, I'm trying to see if the brlaser driver works.

Now I hit the next issue: the 'lpd' backend reports 
'Unable to reserve port: Invalid argument'
And I need to figure out what's causing this--or rather, what the solution is.
Right now, I'm stuck (lpd is the main way to access it, and it isn't working).

Thanks,
Isaac Dunham

---

---

From: Isaac Dunham <[email-masked]>
Date: Sun, 29 Jun 2014 18:28:31 -0700

> Right now, I'm stuck (lpd is the main way to access it, and it isn't working).
OK, now we're in cups-1.7.3/backend/lpd.c:

...the problem is a local implementation of rresvport_af(), trying to reserve
a port but failing.

And strace -p `pidof lpd` says this:
Process 16113 attached
restart_syscall(<... resuming interrupted call ...>) = 0
geteuid32()                             = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 7
bind(7, {sa_family=AF_INET, sin_port=htons(905), sin_addr=inet_addr("0.0.0.0")}, 256) = -1 EINVAL (Invalid argument)
close(7)                                = 0
writev(2, [{"", 0}, {"DEBUG: Unable to reserve port", 29}], 2) = 29
writev(2, [{"", 0}, {":", 1}], 2)       = 1
writev(2, [{"", 0}, {" ", 1}], 2)       = 1
writev(2, [{"", 0}, {"Invalid argument", 16}], 2) = 16
writev(2, [{"", 0}, {"\n", 1}], 2)      = 1
nanosleep({1, 0}, 0x5d2bcae8)           = 0
geteuid32()                             = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 7
bind(7, {sa_family=AF_INET, sin_port=htons(904), sin_addr=inet_addr("0.0.0.0")}, 256) = -1 EINVAL (Invalid argument)
close(7)                                = 0
writev(2, [{"", 0}, {"DEBUG: Unable to reserve port", 29}], 2) = 29
writev(2, [{"", 0}, {":", 1}], 2)       = 1
writev(2, [{"", 0}, {" ", 1}], 2)       = 1
writev(2, [{"", 0}, {"Invalid argument", 16}], 2) = 16
writev(2, [{"", 0}, {"\n", 1}], 2)      = 1
nanosleep({1, 0}, 0x5d2bcae8)           = 0
geteuid32()                             = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 7
bind(7, {sa_family=AF_INET, sin_port=htons(903), sin_addr=inet_addr("0.0.0.0")}, 256) = -1 EINVAL (Invalid argument)
close(7)                                = 0
writev(2, [{"", 0}, {"DEBUG: Unable to reserve port", 29}], 2) = 29
writev(2, [{"", 0}, {":", 1}], 2)       = 1
writev(2, [{"", 0}, {" ", 1}], 2)       = 1
writev(2, [{"", 0}, {"Invalid argument", 16}], 2) = 16
writev(2, [{"", 0}, {"\n", 1}], 2)      = 1
nanosleep({1, 0}, Process 16113 detached
 <detached ...>

Clearly something needs to be adjusted for this to work with musl; I'm not sure what it is.

Thanks,
Isaac Dunham

---

---

From: Rich Felker <[email-masked]>
Date: Sun, 29 Jun 2014 22:03:11 -0400

On Sun, Jun 29, 2014 at 06:28:31PM -0700, Isaac Dunham wrote:
> ....the problem is a local implementation of rresvport_af(), trying to reserve
> a port but failing.
> 

Where did the value of 256 for socklen_t come from? That's almost
surely the cause of the EINVAL. sockaddr_in should have a length of
16, not 256.

Rich

---

---

From: Isaac Dunham <[email-masked]>
Date: Sun, 29 Jun 2014 21:35:13 -0700

> surely the cause of the EINVAL. sockaddr_in should have a length of
Apparently this:
    if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
          return (fd);

addr is of type http_addr_t, defined in cups/http.h thus:
typedef union _http_addr_u              /**** Socket address union, which
                                         **** makes using IPv6 and other
					 **** address types easier and
					 **** more portable. @since CUPS 1.2/OS X 10.5@                                  ****/
										{
  struct sockaddr       addr;           /* Base structure for family value */
  struct sockaddr_in    ipv4;           /* IPv4 address */
#ifdef AF_INET6
  struct sockaddr_in6   ipv6;           /* IPv6 address */
#endif /* AF_INET6 */
#ifdef AF_LOCAL
  struct sockaddr_un    un;             /* Domain socket file */
#endif /* AF_LOCAL */
  char                  pad[256];       /* Padding to ensure binary compatibility */
} http_addr_t;

I'm not sure how to handle this.

Thanks,
Isaac Dunham

---

---

From: Isaac Dunham <[email-masked]>
Date: Sun, 29 Jun 2014 22:34:27 -0700

Thanks to Rich's comment, I've found a solution that works here.
The patch doesn't exactly look nice, though.

And yes, once I add this patch I can print using Peter De Wachter's brlaser
driver (github.com/pdewacht/brlaser).

I'll be sending a patch for main/cups to alpine-devel shortly,
and probably packaging brlaser for alpine.

HTH,
Isaac Dunham
diff --git a/backend/lpd.c b/backend/lpd.c
index 6e4ab36..bbffb82 100644
--- a/backend/lpd.c
+++ b/backend/lpd.c
@@ -1244,6 +1244,7 @@ rresvport_af(int *port,			/* IO - Port number to bind to */
 {
   http_addr_t	addr;			/* Socket address */
   int		fd;			/* Socket file descriptor */
+  socklen_t	socksz=sizeof(struct sockaddr);	/* size of struct sockaddr* */

  /*
@@ -1260,6 +1261,23 @@ rresvport_af(int *port,			/* IO - Port number to bind to */
   memset(&addr, 0, sizeof(addr));
   addr.addr.sa_family = family;
 
+  switch(family) {
+    case AF_INET:
+      socksz = sizeof(struct sockaddr_in);
+      break;
+#ifdef AF_INET6
+    case AF_INET6:
+      socksz = sizeof(struct sockaddr_in6);
+      break;
+#endif
+#ifdef AF_LOCAL
+    case AF_LOCAL:
+      socksz = sizeof(struct sockaddr_un);
+#endif
+    default:
+      break;
+  }
+
  /*
   * Try to bind the socket to a reserved port...
   */
@@ -1276,7 +1294,7 @@ rresvport_af(int *port,			/* IO - Port number to bind to */
     * Try binding the port to the socket; return if all is OK...
     */
 
-    if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
+    if (!bind(fd, (struct sockaddr *)&addr, socksz))
       return (fd);
 
    /*

---

From: Rich Felker <[email-masked]>
Date: Mon, 30 Jun 2014 03:03:53 -0400

> The patch doesn't exactly look nice, though.

I agree it's ugly. The clean way to do it would be to use getaddrinfo
to request an AI_PASSIVE address for the desired family. Then you get
the right sockaddr type and size for free, and you can subsequently
fill in the port to try. That wouldn't work for AF_LOCAL (at least not
on musl) but this whole function makes no sense for AF_LOCAL.

Of course binding a reserved port like this is a serious security
smell -- it sounds like they're trying to facilitate port-based
authentication, which is unsafe if used for anything except localhost.

I would see if it's possible to remove the binding completely and have
it work. Remote lpd's would not be able to trust the ldp that omits
the bind based on its port, but this kind of trust is fundamentally
wrong and insecure anyway. If such a trust relationship is needed, a
proper authentication channel must be used.

Rich

---

---

From: Natanael Copa <[email-masked]>
Date: Tue, 1 Jul 2014 16:19:06 +0200

On Sun, 29 Jun 2014 22:34:27 -0700

> and probably packaging brlaser for alpine.

good catch!

would be nice to know what upstream says about it.

-nc

---