LPD is Dead

Patrick Powell
LPRng.com

papowell@astart.com

Introduction

In LPD Must Die Gerald Carter puts forward a set of arguments that the vintage LPD code must be purged from the UNIX/Linux/Posix environment. In his article he suggests the following goals, which I am paraphrasing:

  1. Featherweight (no spooler) printing to local devices as well as support for the classical print spooling facilities.
  2. Simple method to add filters or access to printing facilities for programs.
  3. Secure system (authentication, privacy, and compromise).

    Some of the things that were not mentioned but I think that we all agree on are:

  4. An easy way to get status reports about jobs or printers.

As Gerald suggests, there are two approaches: take a working system and extend it or create an entirely new system. I was curious just how much effort it would take to extend LPRng to provide these services and was surprised to find that almost all of the desired functionality was already available or it was only necessary a user interface or command line option to access the functionality.

In the following sections I will discuss how lightweight printing, user configuration, security, and status reporting are handled in LPRng-3.7.1 and what are the plans for the future.

Featherweight Printing

LPRng has always supported Lightweight Printing: you do not need a print spooler (lpd) running on your local host and can use a print spooler on some other host. However, if you want to print to a device attached to your local host you still needed to run a print spooler on the local host.

LPRng-3.7.1 now provides Featherweight support: the lpr program can send jobs directly to a printer attached to the local host with full job printing support including filters and banner pages. As an aside, it turned out that the entire mechanism for doing this was already present in LPRng, and it was only necessary to add the appropriate switch statement and subroutine calls to open a local device rather than send the job to a remote print spooler.

Example Command Line:
   lpr -Plw5%9100 file    - open a socket connection
   lpr -P/dev/lp file     - open a device
   lpr '-P|/bin/smbprint' file  - use a program

If you want to have a filter invoked for the job, you can now use the -X userfilter command line option. This will set up the userfilter so that the job files are fed to the userfilter STDIN and its STDOUT will be attached to the output device.

   lpr -Plw5%9100 -X /bin/rasterize file    - open a socket connection
      /bin/rasterize  port 9100 on host lw5

Simple User Configuration - Client Printcaps

In order to make printing configuration easier for users, it would be nice if they could create their own printcap entries or add user level options to an existing printcap entry. LPRng-3.7.1 now supports the User Printcap file ${HOME}/.printcap. The entries in the User Printcap file are only used by the LPRng client programs such as lp, lpr, lpstat, lpq and so forth, and provide information about the printer location and capabilities. The functionality that this information provides can also be provided by command line options.

The options in the User Printcap file entries are appended to options in the system printcap file entries and supplement or override default values. The order of printcap entries for the user is determined by the order in the user printcap file followed by any system entries. This allows the user to specify her default printer as well as the order in which to display printer status.

Example:
  System printcap:
     pr1:lp=pr1@remotehost
     pr2:lp=pr2@remotehost
  User Printcap:
     pr2:append_z=landscape,a4

  Resulting Printcap Information:
     pr2:lp=pr2@remotehost:append_z=landscape,a4
     pr1:lp=pr1@remotehost

The user printcap can be combined with Featherweight printing to allow the user set set up their own printing services. For example, the following entry allows a user to make a connection directly to a network printer and then pass his job files through the filter before sending them to the printer:

     pr2:lp=lw5%9100:filter=/bin/myfilter:direct

Another innovation is allowing users to specify command options as part of the printcap information. For example, the following entry shows how options to the lpr and lpq command can be specified:

     pr1:lpr=-Cforms
        :lpq=-lll

The user can also restrict the number of printers that are displayed for status information by using the all printcap entry. For example, the following entry will cause the lpq client to show only status for printers p2, p5, and p6:

  User Printcap:
     all:all=p2,p5,p6

Future releases of lpq will also support the -g p2,p5,p6 command line option that will allow users to show status for a group of printers.

Graphical User Interface

While currently not part of the LPRng distribution, the LPRngTool developed by Geoff Silver and Patrick Powell provides a GUI for printer management. This program is currently under development and testing and provides a very simple interface for novice users to set up and configure their printers as well as support for advanced system administrators who can also use it to manage enterprise level printing systems.

Security

There are many ways that the term security gets used: authentication, privacy, and compromise are just a few. Rather informally, authentication means that you have to have some way to identify that the user who makes a request is the real user, and that the print server/printer who is servicing the request is the real print server. Privacy means that information that you do not want disclosed does not get disclosed. And finally, compromise means that by using this facility you do not allow the users of the system to modify some aspect of system security (notice the recursive definition).

LPRng already supports authentication by using Kerberos, PGP, or simple MD5 authentication. Also, you can add your own modules or use PAM modules if you wish to have enhanced capabilities.

A simple concept of privacy is that by using this facility you will not expose or make available information to third parties that you do not want exposed. The type and amount of privacy is very difficult to specify. Currently LPRng provides 'transport' privacy when transferring jobs over the network by using Kerberos or PGP and their encryption support. It provides 'storage' privacy by storing job related files in a directory which should be owned by a special user (daemon or lp), and making the files readable only by the special user. However, experience with 'visibility privacy' where only the users who submitted jobs could see status about their jobs indicated that the problems of administration and management were greatly increased if the user name, host, and job ID were not globally visible. Administrators who tried to 'blackout sensitive information' soon found that users were demanding system administration privileges and that the number of trouble calls about mystery jobs locking up print queues increased out of all proportion. They quickly returned to the original user@host+jobid information display.

Compromise is much more difficult to both define and to agree upon a definition. However, in general there is a notion that a user should not be able to use a system facility to 'gain' more privileges than she currently has, or grant other users more privileges than they are untitled to. Unless, of course, they have the privilege of granting privileges, and then all bets are off... but I digress, as we are back to the problem of the root user.

The biggest obstacle to providing a compromise free system is the existence of various Operating System restrictions and system interoperability requirements. In particular, the RFC1179 (Line Printer Server Protocol) requires that the LPD server listens for incoming requests on port 515, and that it originate outgoing requests on ports 721-731. In all known non-capability based Operating Systems, this forces the LPD server to run as user root so that it can bind to these ports.

While the LPRng lpd server does not insist that connections originate from ports 721-731, almost all known print spoolers provided by vintage and legacy operating systems such as SunOS, HPUX, Solaris, DGUX do. And there are a wide range of Network Print Server appliances that require connections to originate from low port numbers as well.

An obvious solution to the low port problem is to first bind to port 515 and then drop all root privileges. This would allow full interaction between LPRng systems as well as allowing non-LPRng systems to submit jobs to LPRng. The minor problem is that LPRng would not be able to send jobs to the non-LPRng systems that insisted on connections originating from a privileged port. This is usually not a problem with Network Print Spoolers, as most of these allow jobs to be sent via the LPD network interface or to a TCP/IP port. Other print spoolers can be replaced with LPRng or they can simply be configured to act as job forwarders. This is currently supported by the lpd drop_root configuration option.

The clear and obvious solution to these problems is to use an Operating System that supports capability based security and assign the LPRng programs 'bind to low port' capabilities. Also the LPD server should run as a 'special' user (daemon or lp). Having done this, the LPD server will have greatly reduced the possibility of being used for system compromise.

The good news is that developers are working on adding capability security options to various Operating Systems. The bad news is that lots of different developers are working on lots of different ways to add and manage these facilities. The really bad news is that most of these require special compile time operations as well as run time libraries that are not present on all target systems, making software distribution even more painful than it currently is.

Since LPRng does run as root and is a network based facility it will be exposed to hacker attacks. The most popular types of attack are the stack overflow attack and the insideous 'format string' attack. The stack overflow attack is usually (but not always) based on exploiting the use of the functions such as sprintf() that do not perform bounds checking on their output. LPRng does not use the system printf() library support except for one very carefully controlled routine which uses the native snprintf() to format a long double floating point number.

The 'format string' attack exploits the POSIX printf() format '%n' capability. This innocuous looking item uses a parameter value as an address and causes printf() to write a value to this address. This is similar to the stack overflow attack but can be used to put values in other sensitive areas. The LPRng version of sprintf() does not support %n for exactly this reason.

However, it is difficult if not impossible to guarantee that some low level system library is not using sprintf or the %n format. So for this reason LPRng tries to use as few non-LPRng provided libraries or faciltities as possible. Even then there are various library routines that use sprintf. Until the sprintf() function and the '%n' are eradicated, this will continue to be a source of concern.

Status Notification

The Printer Working Group has been trying to define a network protocol to be used to notify users and system administrators about problems and print job status. This functions only with the new IPP printers and does not handle legacy printers. However, Ben Woodard of VA Linux has come up with a rather clever solution: define a simple multicast printer status protocol and provide a set of multicast clients for printer information. This allows not only the new IPP based printers to provide information, but you can also support vintage or legacy printers as well.

Currently, LPRng has the necessary infrastructure to add support for informing clients via the multicast protocol. It can generate status messages or updates when a job is submitted, has its status changed via administrative action, is started printing, and when it has finished printing. In addition, a printer can be monitored while active, and any error or status messages reported as well.

Summary

The LPRng system was designed to replace the existing LPD print spooler system with greatly improved functionality. The latest version addresses the problems of Featherweight Printing, User Configuration and Security. In addition to these features, LPRng will compile and run on all known UNIX or POSIX based systems.

Toss your LPD, SystemV LP, PrintSuite, or other spooler system and replace it with LPRng.

LPD is dead.