LPRng - An Enhanced Printer Spooler Introduction and Reference Manual Version 3.1, Jan. 1, 1997 Patrick Powell ABSTRACT The LPRng software is an enhanced, extended, and portable version of the Berkeley LPR software. While providing the same general functionality, the imple- mentation is completely new and provides support for the following features: lightweight (no databases needed) lpr, lpc, and lprm programs; dynamic redirec- tion of print queues; automatic job holding; highly verbose diagnostics; multiple printers serving a sin- gle queue; client programs do not need to run SUID root; greatly enhanced security checks; and a greatly improved permission and authorization mechanism. Introduction Print spooler software is one of the most common and heavily used system application programs. While printing may appear to be simple on the surface, in practice it is complicated by the following problems. Each model of printer has a peculiar set of interface and format requirements; this means that the printer software must be highly configurable at the device interface level. Next, multiple users may want to share the same printer; this leads to the need for a spooling system with the associated problems of priority and fair use. Printers are notorious for failing at the most inopportune times; the spooling software needs to report failures and to reconfigure or repair the system in a simple manner. Finally, the software should be portable so that the same software can be used on different systems; in a network based system this introduces the problems of security and authentication. The LPRng Printer Spooling[Pow95] software is a descendant of the 4.3 BSD Line Printer Spooler Software (LPR),[Cam94] but has totally redesigned and reimplemented. The evolution started in 1986 at the University of Waterloo, where the original 4.3 soft- ware was modified to support a variety of new printers. Due to restrictions with the original AT&T and Berkeley software license these modifications could not be distributed. The problems encountered during this process led to the development of the PLP (Public Line Printer) software[Pow95a] and PLP Version 3.0 (PLP3.0) was released in 1988. The PLP software architecture was based on the the original LPR code, but with highly verbose diag- nostics and a much more elaborate set of administration func- tions. From 1988 to 1994 various sites and administrators modified and extended the PLP3.0 software. The plp@iona.ie mailing list was formed to distribute and coordinate these changes, and in 1994 a major programming effort by Justin Mason restructured the PLP3.0 code, integrated the majority of exten- sions, and PLP4.0 was released in 1995. Problems with the PLP software were discussed in the plp@iona.ie mailing list as well as various USENIX newsgroups. Given the current network security issues, client/server based applications, and growing administration problems, the PLP4.0 software needed extensive revisions. There was general agreement on the following design goals. LPRng - Introduction 1 First, run time diagnostics and detailed error reporting were essential and should be the highest priority. When problems occur users and administrators must quickly diagnose the causes, and obtaining information is essential. Next, the user interface to the printing facilities should change as little as possible. This would allow a gradual evolution from LPR and PLP to the new software with as least surprises to the users as possible. How- ever, the administrative interface could change, and many improvements and changes were suggested. It was essential that the new software be compatible at the network interface level with other implementations of the LPR spooling software. While in 1990 the RFC1179 - Line Printer Daemon Protocol[McL90] docu- menting the network protocol to be used to transfer print jobs and status information between line printer spooling programs was published, many of the existing implementations do not conform to RFC1179 or have made extensions to the RFC. The existing LPR and PLP software uses a set of filter programs to interface to vari- ous printers. A major concern of administrators was that these vintage filter programs should be usable with the new software. Finally, the long list of security, administration, and network- ing problems should be eliminated if at all possible. These considerations led to the design and development of the LPRng software. While it is a totally new design and implementa- tion of spooling software, it uses routines and support code from the Free Software Foundation GNU Project, and is distributed under the GNU Copyleft License.[GNU91] The LPRng software was intentionally designed to use as few non-portable or non-standard Operating System facilities as possible, or to use them in a highly controlled and portable manner. The use of the GNU utili- ties such as autoconf and Gnumake allow operating system depen- dent versions of various support routines to be selected at com- pile time in an automatic manner. Since the original release of LPRng in 1994, there has been growing use of it for commercial and other business applications. The Artisitic license meets the needs of most end users; a com- mercial license and support is available for users and institu- tions that require it. In addition to the original goals, Ver- sion 3.1 of LPRng now provide the following capabilities: o Unique identification of user jobs. o Long job numbers (up to 6 digits long), which avoids problems when spooling a large number of jobs to a single spool queue. o Dynamic redirection and routing of jobs. A spool queue can now duplication and redirect a job to one or more spool queues. This allows dynamic routing of jobs based on load conditions and other considerations. o Authenticated job and command transfers between users and servers. The original LPR protocol as defined in RFC1179 has been extended to provide for authentication. The actual authentication is separate from LPRng, which provides an interface and specification for its use. Currently, PGP and Kerberos authentication is supported. The following sections discuss the overall architecture of the LPRng software, and then deal with the major components. The emphasis of this discussion are the added functionality or 2 LPRng - Introduction differences of LPRng. The LPRng configuration information, extensions to the printcap database, and changes to the lpr and other client programs is discussed. The operation of the job spool queues and the new algorithm used for job printing is then covered, together with a description of the filter interface mechanism. Security and associated problems with SETUID ROOT programs is briefly discussed, and the summary at the end lists some outstanding issues. LPRng Software Architecture The LPRng software architecture is shown in Figure 1. ------------------------------------------------------------------ LPRM LPQ LPC t2 server (LPD) Filters +++ + +++++ ++ +++++ +++++ +++++ ++ + LPR +++ LPD +++++++++++++ LPD +of + | | + | | +bp + + file t1@h1 t2@h2 + +if /usr/export/LPD/t1 /usr/spool/t2 + Databases control.t2 + +++++++++++ + + config + cfA003h1 cfA001h1 + +++++++++++ dfA003h1 dfA001h1 lp +++++++++++ hfA001h1 (/dev/lp) +printcap++ dfB003h1 +++++++++++ permissions cfA006h2.com cfA004h1 dfA006h2.com dfA004h1 Figure 1: LPRng Spooling Software Architecture LPRng - Introduction 3 While LPRng is similar in structure to the Berkeley LPR software, it differs in many important details. The dashed lines indicated TCP/IP based communication between two programs; solid lines rep- resent access to files or directories. Boxes with dotted out- lines represent databases that may be accessed by all programs, either as files or by using network facilities. The user pro- grams such as the print spooler lpr, the status reporter lpq, the job remover lprm, and the control program lpc are client programs which connect to one or more lpd server processes using TCP/IP. After validation and authentication the servers carry out requested activities on files and/or provide status information. The configuration and printcap databases provide the information needed by both server and client programs. While clients do not need access to the printcap database, in many cases a runt database is useful for providing printer configuration informa- tion. As in the LPR software, the lpd server manages one or more spool queues where print jobs are stored. These are are imple- mented as directories in a file system. A print job consists of a control file, which contains user information and printing options, and data files which contain the actual information to be printed. A spool queue can be a bounce or forwarding queue, which temporarily stores print jobs before they are transferred to another queue, or a print queue which has an associated printer. Operation of a spool queues is controlled by information in 4 LPRng - Introduction the spool queue printcap entry and the printer control file in the spool directory; individual print job may also have a job control file as well. -#-ENG-LPRng-Test-Configuration----------------------------------- # compile time only: #client_configuration_file /etc/lpd.conf:/etc/lpd_client.conf #server_configuration_file /etc/lpd.conf default_printer t1 default_host %H default_banner_printer /usr/local/bin/lpbanner lockfile /usr/spool/LPD/lpd.lock logfile /usr/adm/lpd.log #lpd_port printer lpd_port 4000 originate_port 721 731 user daemon group daemon #printcap_path /etc/printcap:/usr/etc/printcap printcap_path /tmp/LPD/printcap.%H #printcap_path |/tmp/LPD/pcserver #perms_path /tmp/LPD/printer_perms.%H #perms_path /etc/printperm:/usr/etc/printperm perms_path /tmp/LPD/printer_perms.%H #print_perms_path |/tmp/LPD/permserver use_info_cache yes # include facility include /tmp/LPD/common.conf Figure 2: Configuration Database Format LPRng - Introduction 5 Jobs are submitted to the lpd server by the lpr program which transfers the job over a TCP/IP connection. The lpd server then forwards the job to another server or print it. The lpq program requests and prints job status information, and the lprm program removes jobs from the spool queue. The LPRng software uses a permissions database and the printcap information to determine if a user is authorized to use a facility; authorization can be based on originating host, user name, and a variety of other attributes. After a job is placed in a print queue, lpd creates a server process to manage the printing operations. This server process then creates one or more filter processes which interface to the printer hardware. The data files are passed through the filters to the actual printer. Configuration Information Configuration information is used by both the LPRng clients and the lpd server. The configuration information controls the network behavior of the programs, and provides a set of default for commonly specified system information. Compile time defaults can be overridden by values read from a configuration file, whose format is shown in Figure 2. The configuration file can also be used to specify default values for printcap variables. In all LPRng database files leading whitespace, blank lines, and lines whose first non-whitespace character is a # are treated as comments and ignored; a \ as the last character of a non-com- ment line will logically continue this line to the next line, replacing the \ with one or more spaces. 6 LPRng - Introduction Each line of the configuration file has a configuration vari- able and its value. The client_configuration_file and server_configuration_file values are used only at startup and initialization, and specify the configuration files for the LPRng client and lpd server programs. Each of the configuration files is read in sequence and variable values are updated as the files are read. Much of the configuration information provides site dependent information or allows configuration for testing. The default_printer and default_ host variables set the default printer and host to be used by client software; the %h and %H strings are replaced with the short or fully qualified domain name of the host on which the software is running. The default_ banner_printer sets the default banner printing program to be used by the lpd server; the lockfile and logfile are used by the lpd server to prevent multiple servers from running and to record lpd logging information. The lpd_port variable specifies the TCP/IP port on which the lpd server listens for client requests. In production versions this is usually 515 (the printer alias in the network service database); by setting it to some other port a test version can be run in parallel with production software. The originate_port value specifies a range of TCP/IP port num- bers for originating connections. RFC1179 specifies that these connections should originate from port 721 to 731 inclusive; in most UNIX environments these are privileged ports and cannot be used unless the program's effective UID is ROOT (0). On a UNIX system, if the client software is not SETUID ROOT, then only the ROOT user can successfully bind to a privileged port. See Secu- rity Considerations for details on problems this may expose. The user and group entries specify the effective user and group IDs to be used by the lpd server. For this to be effective, the lpd server must be SUID root or be started by a root process; see Security Considerations for details. The printcap_path, lpd_printcap_path, and printer_perms con- figuration information specifies where database information will be found. All programs use the printcap_path, and printer_perms information; the lpd server will use the lpd_printcap_path infor- mation after the printcap_path informaiton. The use_info_cache option allows the lpd server to read the information once at startup and then use a cached copy of this information, as does the inet.d server. If lpd receives a SIGHUP signal it rereads the database information. This can be done by using the lpc reread command. Finally, it is possible to use the include facility to read additional configuration files. This facility may be removed in later releases of the LPRng software. Printcap Information Entries in the printcap database define spool queues and their configuration available to the LPRng software. Figures 3a and 3b show a set of client and server printcap database entries. Lead- ing whitespace, blank lines, and lines whose first character is `#' are ignored. Default values for printcap variables are set in the configuration file, using the same tags as the printcap LPRng - Introduction 7 file. For compatibility with the historical LPR printcap format, \ at the end of a line appends the next line to the current line. -#-Client-Printcap-Database--------------------------------------- # printer p1@'local host' p1 # remote printer p2 |full|double|rotate |twosided|XDR Line Printer :lp=p2@host # remote printer alternative p3:rp=p3:rm=host # connect to port 2000 p4:lp=host%2000 # all entry (lpq -a) all:all=p1,p2,p3 Figure 3a: Client Printcap Examples ------------------------------------------------------------------ A printcap entry consists of a primary name, an optional set of aliases, and a set of variable tag names and values. The pri- mary name is the name by which the printer is referred to in error messages and status information. The | separator starts an alias entry and the : separator starts an variable entry; entries extend to the end of line or the next separator character; lead- ing and trailing in each entry whitespace is ignored. The LPRng client programs need only the lpd server host name and target printer on the server. This can be specified on the command line using the `-Pprinter' or `-Pprinter@host' option; if no default is specified in the configuration information the local host is the default server host. In Figure 3a, the simple printcap entry p1 means printer p1 on the default host; entry p2 has has two aliases, the last of which is really a comment and will be used when displaying status information. The lp (line printer) tag specifies the printer device or host. The form lp=printer@host is printer on host; the form lp=printer@host%2000 indicates the lpd server is available on port 2000. This last form is extremely useful when running mul- tiple versions of spooler software, and for connecting to network based printers with specialized needs. A file pathname such as lp =/dev/ttya specifies a printer device to be used by the server; the form lp=host%2000 indicates port 2000 on host is net- work based printing device. More printcap information is needed for the lpd server, as is shown in Figure 3b. Spool queues have printcap entries with a sd (spool directory) tag. The tc tag (recursively) appends a print- cap entry to the end of the referencing entry. Multiple tc tags may appear in a printcap entry. Printcap entries whose primary (first) name starts with a non-alphabetic character are consid- ered to be dummy entries and can only be referenced by tc tags. ------------------------------------------------------------------ # Server/Client Printcap Database # file: /etc/printcap # clients see p1 as remote pr # server use sd tag to get 8 LPRng - Introduction # /usr/spool/LPD/p1/printcap p1 :cm=Test Printer 1 :sd=/usr/spool/LPD/p1 :lp=p1@host # second printer, p2 :sd=/usr/spool/LPD/p2 :tc=@common # common information @common: :lf=log :rw :of=/tmp/LPD/psof :if=/tmp/LPD/psif p3:sd=/usr/spool/%P:tc=@common # Printer specific information # used by server, # file: /usr/spool/LPD/\ # p1/printcap # Alternately, this information # could be part of the # /etc/lpd_printcap file p1 # override previous value :lp=/dev/ttya :lf=log :rw :of=/tmp/LPD/psof :if=/tmp/LPD/psif # debug # :db=9,remote=10 # autohold - hold all jobs on submission # :ah Figure 3b: Server/Client Printcap Examples ------------------------------------------------------------------ The lpd server checks to see if a printcap file is in the spool directory, and will read the printcap information from this file, overridding existing information. This allows a single master printcap database to be used by both clients and servers; the clients ignore the sd tags and the server gets printer spe- cific information from the printcap file in the spool directory. The oh (options for host) entry can be used to specify that the printcap entry is used only by a host whose IP address matches the IP address of the entry. For example, if oh=astart2.astart.com, then only hosts with the same IP address as astart2.astart.com would use the printcap entry. By using the oh entry in the server printcap entry a single printcap database file can be used. A major administration problem is the distribution of printcap information. One solution is to use a network database such as Sun Microsystems NIS, HESIOD, Sybase, etc. Rather than build in a specific database access method the LPRng software uses the LPRng - Introduction 9 concept of database filters to access the information. In Figure 2, the configuration printcap_path value |/tmp/LPD/dbserver spec- ifies using a filter program to get printcap information. The filter program is started by the client or server process and a string containing the name of the desired printcap entry is sent to the filter's stdin port; the returned printcap informa- tion is read from the filter's stdout port. By convention, a all request returns either all the available printcap entries, or an all printcap entry whose all tag contains a list of available printers. Key----------Match-Connect-Job---Job----LPQ--LPRM--LPC------------ Spool Print SERVICE S 'X' 'R' 'P' 'Q' 'M' 'C,S' USER S - JUSR JUSR JUSR JUSR JUSR HOST S RH JH JH JH JH JH GROUP S - JUSR JUSR JUSR JUSR JUSR IP IP RIP JIP JIP RIP JIP JIP PORT N PORT PORT - PORT PORT PORT REMOTEUSER S - JUSR JUSR JUSR CUSR CUSR REMOTEHOST S RH RH JH RH RH RH REMOTEGROUP S - JUSR JUSR JUSR CUSR CUSR REMOTEIP IP RIP RIP JIP RIP RIP RIP CONTROLLINE S - CL CL CL CL CL PRINTER S - PR PR PR PR PR FORWARD V - - SA - SA SA SAMEHOST V - SA - SA SA SA SAMEUSER V - - - SU SU SU SERVER V - SV - SV SV SV KEY: JH = HOST host in control file RH = REMOTEHOST connecting host name JUSR = USER user in control file CUSR = REMOTEUSER user from control request JIP= IP IP address of host in control file RIP= REMOTEIP IP address of requesting host PORT= N connecting host origination port CONTROLLINE= pattern match of control line in control file FW= IP of source of request = IP of host in control file SA= IP of source of request = IP of host in control file SU= user from request = user in control file SA= IP of source of request = IP of server host Match: S = string with glob wild card, IP = IPaddress[/netmask], i.e.- x.y.z.w/a.b.c.d or x.y.z.w/N where N is length of mask N = low[-high] number range; NOT negates the test status Figure 4: Permission Attributes 10 LPRng - Introduction The Sun NIS database can be access by using a simple shell script and the ypmatch program; HESIOD, DBII, Sybase, and other databases can be supported in the same manner. The actual printcap expansion algorithm is as follows. The list of printcap files specified by the configuration database values printcap_path and on the LPD server the additional lpd_printcap_path are searched. These values should be semicolon or comma separated lists of files, or the command for a filter. The files are read, and any include files are read at the indi- cated points. (This is similar to the manner in which the C lan- guage preprocessor operates.) Next, the input is parsed into printcap fields, and organized into raw printcap entries. The raw entries are then sorted and joined together to form the final printcap entries. As each entry is added, it is checked for a tc field and the specified entry is recursively processed. Strings with %X in them will be processed and the string sub- stitions will be made. Currently, %P, %H, %h, %R, %M are replaced by the printer name, fully qualified host name, short LPRng - Introduction 11 host name, remote printer, and remote host respectively. The result of this process will be a set of printcap entries whose values are organized in sorted order. The resulting printcap entry can be examined using the lpc program printcap command. The printcap database is consulted only when actual informa- tion about a printer is needed. When an actual printcap entry is needed, the database is checked to see if a printcap entry with the printer name is present. If it is not and a filter has been specified in the printcap_path configuration information, then the filter started and the required printer name is made avail- able on the filter stdin (file descriptor 0). The filter will write information to its stdout (file descriptor 1), which is in turn read by the LPRng software. The result is then parsed and checked as for the printcap entries obtained from files. When the tc entry to be expanded is not in the printcap database and a filter is available, then the filter will be invoked to obtain the entry. If the first printer name in the printcaps entry is non-alphabetic character, then the entry can only be used as a reference for tc. Job Submission The lpr client program submits jobs to the lpd server by sim- ply using a TCP/IP connection and sending the files to the server. The only information the client needs is the printer and hostname, and can run as a user application. If the printer output is piped to the lpr client, then RFC1179 allows the output to be directly copied from the client to the server by using the lpr -k (for seKure) option. While LPRng sup- ports this option, many other LPR server implementations are defective or do not support this capability. This is useful when creating large jobs, or there is are security related problems with creating a temporary file on the client host. The LPRng clients can run as ordinary user processes; elimi- nates any problems with unauthorized access to files, as the client has no permission except those of the user. However, for the lpr client to be compatible with vintage LPR spooling software (i.e.- SUN Microsystems), it must originate a connection from a privileged port. For this reason, when run as a SETUID ROOT program, after making a connection to the the server, the lpr client uses setuid(2) to drop the root permis- sions, and operates as an ordinary user program. Several of the vintage lpr options such as the `-s' (use sym- bolic links) are not supported; the symbolic link option has no effect as files are transferred directly to the server. Permissions and Authorization Checking One of the requirements of any printer spooling system is to deny access to unauthorized users and to record accounting infor- mation for authorized users. The LPRng software uses a rather elaborate permissions and authorization mechanism, similar to the ones used by computer network firewalls. Since all spooling operations are carried out by the lpd server, it is the only process that needs to perform permissions checks. Permissions are checked when a connection is made to the 12 LPRng - Introduction server, and before the server performs and action or provides information requested by the various client programs. In addi- tion, the server checks job permissions before it prints a job as well as when the job is submitted. This allows NFS based printer spooler software, which copies control and data files directly to a spool directory, to be used with the LPRng software. See the Security Considerations section for a discussion of problems related to allowing this type of activity. -#-Permissions-Database------------------------------------------- # Reject connections not in our subnet REJECT SERVICE=X NOT IP=130.191.0.0/255.255.0.0 # Allow root on trusted hosts or server # to have control and removal capability # and users on the same host to remove their jobs ACCEPT SERVICE=C,M HOST=hop.sdsu.edu,skip.sdsu.edu \ PORT=721-731 USER=root ACCEPT SERVICE=C,M SERVER USER=root ACCEPT SERVICE=M SAMEUSER SAMEHOST REJECT SERVICE=C,M # do not allow forwarded jobs from anybody but dickory ALLOW SERVICE=R NOT SAMEHOST HOST=dickory.sdsu.edu REJECT SERVICE=R NOT SAMEHOST # Allow PC lab to spool to laserwriter ACCEPT SERVICE=R,P,Q PRINTER=lw4 HOST=*.eng.sdsu.edu # if no match in other database then you fail DEFAULT REJECT Figure 5: Sample Permissions Database LPRng - Introduction 13 Each request for service has a set of attributes and values; a list of these attributes is shown in Figure 4. Figure 5 shows a sample permissions database. Each line in the database consists of a match result and a list of attribute names and match pat- terns. Permissions checking is done by scanning the database in order, checking each line for a match. If all the entries on line match, then the result is the match result for the line or the current default. Note that each entry can have several alternate patterns; these patterns are tried in order until a match is found. The default_permission configuration variable specifies an initial (default) permission database entry; additional permis- sion databases are specified by the perms_path configuration variable. When checking permissions for a spool queue with printcap entry, the xu printcap tag provides an additional set of databases to be searched as well. One of the database entries can be a filter, which is invoked with the filter_options speci- fied in the configuration database, and has the name of the printer written to its standard input. The filter options include the print job user name, which can be used to search a database to determine if the user has permission to access a file. The filter output is used as an additional permission file for permissions checking. For a complete list of keys and tags, see the manual page for details. If no match is found after searching all specified databases then the last specified default permission will be used. Permission attributes are treated as string, integer, or IP address values. The string patterns are based on the simple glob patterns of the Bourne and C shells, and use case insensitive matching with only the * metacharacter. For example, the pattern A*b will match Ab, and AthisB. IP address patterns are an address (ADDR) followed by an optional netmask (NM) which defaults to 255.255.255.255; the match succeeds if (using C 14 LPRng - Introduction language notation) (IP^ADDR)&NM is zero. For example, the pat- tern 130.191.163.0 / 255.255.255.0 matches all of the addresses in the 130.191.163.0 subnet range. The netmask can also be spec- ified by the number of most significant non-zero bits. For exam- ple, 130.191.163.0/255.255.255.0 and 130.191.163.0/24 are the same address/mask pair. Number patters are a low to (optional) high integer range. The special pattern char= pattern matches the char line in the job control file against pattern. For example, C=A*,B*,C* will check the C (class) information line for a string starting with A, B, or C. The special pattern NULL matches missing or no information; for example the permissions entry ALLOW SERVICE=R,P USER=NULL,* allows anonymous job spooling and printing. Spool Queues and Job Files The main activity of the lpd server is centered on managing print jobs in the spool queues. A print job consists of a con- trol file, containing user and other information, and data files containing the information to be printed. The control file for- mat is specified by RFC1179; a sample job control file is shown in Figure 6. Control file names have the format cfXnnnHOST, where X is a letter, nnn is a 3 digit job number, and HOST is a host identifier. Data files names have the format dfXnnnHOST, where X is a letter, and nnn and HOST are identical to the corre- sponding control file. -Htaco.astart.com------------------------------------------------- Ppapowell J(stdin) CA Lpapowell Qt1 fdfA917taco.astart.com N(stdin) UdfA917taco.astart.com Figure 6: Job Control File ------------------------------------------------------------------ Control file lines starting with an upper case letter provide information and those starting with lower case letters specify a format and a data file to be printed with the format. For exam- ple, the P (person) and H (host) lines give the originating user and host name; the I (indent) and L (banner name) are used when printing the job. The LPRng software extends the basic RFC1179 control file entries by adding Z (output filters options), Q (original queue), and A (identification) options. The value of these options are passed to the filters that format and print the data files. For example, Figure 3a shows an example of a printcap entry (p2) with several aliases. The lpr command lpr -Q -Pdouble -Zheavy_paper will create a control file with the Qdouble and Zheavy_paper entries and sends it to the p2 printer. The output printing can use the Q and Z entries to select various paper and format options. LPRng - Introduction 15 LPD Server Operations The lpd server creates queue server process for each spool queue, and then waits for connections from clients. Each time a request arrives the server will create a new process to handle the requests. The max_servers_active configuration variable can be used to limit the number of active servers. The queue server process uses the printcap entry information and a set of control files in the spool directory to control its activities and report its actions (Figure 1). In the discussion below, printer is stands for the primary printer name; all files are in the spool directory unless otherwise indicated. The Server lock file (printer) is used to ensure that only one server process is active at a time. The spool control file (con- trol.printer) has the format shown in Figure 7a, and controls one or more of the spool queue related activities. Entries in this file override defaults and values in the printcap database. Note: the information shown in this file may not be present at all times. The control file spooling_disabled and printing_ disabled entries disable spooling to the queue and printing from the queue respectively. The redirect entry causes the server to transfer all spool jobs to the specified remote printer. When holdall is enabled, the server will not process a jobs until it is released by a request from the lpc program. The printcap ah (automati- cally hold) flag can be used to set job holding on by default, or it can be enabled/disabled by using the lpc holdall or noholdall commands. If the ah flag is on, it cannot be overriden by the lpc holdall/noholdall commands. -printing_disabled-0---------------------------------------------- spooling_disabled 1 debug 10,remote=5,log=/tmp/log redirect p3@mentor holdall off class A,B Figure 7a: Spool Control File ------------------------------------------------------------------ The class entry restricts the printable jobs to the specified class. This facility allows special forms to be mounted on a printer and only jobs which need them to be printed. The special pattern char=patterns restricts printing to jobs with a control file line starting with char which matches pattern. For example, P=accounting could be used to restrict printing to jobs from the accounting user. The debug entry is a diagnostic and testing aid. The set of options are used used by the server to enable or disable specific testing functions. For example, 10,remote=5,log= /tmp/log speci- fies a general debugging level of 10, setting the remote flag to 5, and logging to the /tmp/log file. The lpc (line printer control) program is used to request the lpd server to change the spool control file values and take other actions, such as starting or stopping server processes. The lpc program can also request (brutal) spool server process termina- tion, and (gentle) restarting of spooling activities. The lpc stop and start commands are used to enable and disable printing; 16 LPRng - Introduction enable and disable is used to enable and disable spooling. The abort command will attempt to brutally stop printing of the cur- rent job and remove it; the kill command will stop printing and then attempt to restart the last job. There are similar commands to modify the various fields in the control file; see the lpc man page for details. The spool server process scans the spool queue, ordering jobs to be serviced in a first-in, first-out order within priority classes. Class A is the lowest (default) priority, and Z is the highest. When a job is selected for for servicing, the spool server forks a subserver process to carry out the actual work.. The reason for using a subserver process for per job servicing is based on experiences with a variety of UNIX implementations. Some of these implementations have memory leaks or file descrip- tor leaks associated with various database and networking rou- tines; each time a process uses these routines they open a new file descriptor or allocate some temporary storage. Unfortu- nately, these descriptors are never closed the descriptors or reclaim the storage. These defective functions are firewalled in a subserver process, which only exists while a particular job is processed. Note that the same problems exist in the lpd server, which also takes care to isolate these actions in a subserver process. -active-----2743-------------------------------------------------- hold 1 priority 0x873486 remove 1 redirect p4@mentor error Printer timed out Figure 7b: Job Hold File ------------------------------------------------------------------ When a job is selected for service, the subserver process cre- ates a job hold file to record information; job cfA001mentor will have hold file hfA001mentor. The hold file has the format shown in Figure 7b. The active entry records the process ID of the subserver pro- cess, and indicates that the job is active. A non-zero hold entry indicates that the job is being held by administrative actions; a hold value of 0 allows a job to be printed. The lpc hold and release commands can be used to hold and release jobs. The priority field specifies an additional level of job prior- ity; jobs with non-zero priority fields are serviced before jobs with 0 fields; the lpc topq command updates the priority value. The redirect entry supplements the spool queue redirect infor- mation. This entry allows individual jobs to be moved to another spool queue. The lpc move command updates the redirect value. The remove and error entries are used to solve a problem with defective or misconfigured printing software. After a job is serviced its files are removed from the spool directory. How- ever, sometimes due to accident or intent, the files cannot be deleted, resulting in the job being endlessly printed and pre- venting normal operations. When a job is serviced, the job hold file is created and written in the spool directory; if the hold file cannot be modified the job is not serviced. After the job LPRng - Introduction 17 has been serviced the remove field is set to a non-zero value; this prevents the job from being reprinted, and the error field records any error conditions that might inhibit retrying servic- ing the job. This information is displayed by the lpq (line printer queue) program. After the job files have been successful removed, the server then removes the job hold file. A bounce queue is used to temporarily hold jobs until they can be forwarded to a remote printer. This is useful when sending jobs to a network printer. The LPRng software lpr and lpd pro- grams use the same algorithm to check file permissions and acces- sibility when sending jobs to a remote printer. Normally, data files are not modified when forwarding, but if the printcap bq=destsystem flag is set and there is an appropriate format fil- ter, the data files will be processed by the filter before trans- fering to the destination system. Note that for correct opera- tion, the printcap lp flag should be set to the name/host combi- nation of the bounce queue, i.e.- -LP-=-open(-'lp'-);--//-open-device------------------------------- OF = IF = LP; // set defaults if( 'of' ) OF = filter( 'of' ) -> LP; // make OF filter if( accounting at start 'as') do accounting; if( leader on open 'ld' ) `ld` -> OF; // send leader if( FF on open 'fo' ) `fo` -> OF; // send FF // check to see if banner required do_banner = (always banner 'ab' || (!suppress banner 'sb' && control file 'L' )); if( ! header last 'hl' && do_banner ){ BP = OF; bnr = null; if( banner start 'bs' ) bnr = 'bs' else if( banner program 'bp' ) bnr = 'bp' if( bnr ){ BP = filter( bnr ) -> OF; } short banner info -> BP; if( BP != OF ) close( BP ); } // suspend the OF filter if( OF != LP ) suspend OF filter; Figure 8a: Printing algorithm used by LPRng 18 LPRng - Introduction bqname:lp=bqname@host :bq=destq@host :sd=/var/... :if=/if_filter The :lpr_bounce: printcap flag will cause the LPR program to perform filtering before sending the jobs to a server. This can have unexpected results if the filters are not available on the local host. Printing Algorithm On the surface, dealing with the printer hardware should be quite simple: the printer device is opened, the job data files are sent to the device, and the printing device is then closed. The actual algorithm used by the lpd server for printing a job is rather complex, in order to deal with the following problems. 1. Each printer usually has specific requirements for connection and initialization, not to mention the actual transmission of data. 2. If the connection to the printer is a serial line, stty(1) (or a similar function) must set the speed, format, and other characteristics. When a serial line is closed and reopened the line characteristics may be reset to some default value, requiring the line to be held open throughout the printing process. 3 The effects of the failure printing a job job should be LPRng - Introduction 19 localized to that job. -for-each-data-file-df-in-job-do---------------------------------- // send FF between files of job if( !first job && ! suppress FF 'sf' ){ if( OF != LP ) wake up OF filter; 'ff' -> OF; if( OF != LP ) suspend OF filter; } // get filter for job ?F = LP; // default - no filter format = jobformat; if( jobformat == 'f' or jobformat = 'l' ){ format = 'f'; } filter = format filter from printcap; if( filter ){ ?F = filter( filter ) -> LP; } // send data file to printer // through filter data file -> ?F; // kill filter if( ?F != LP ) close( ?F ) endfor Figure 8b: Printing algorithm used by LPRng 20 LPRng - Introduction 4 Different types of output such as raster plots, PostScript files, text files, etc., may require different handling when printing. This can be very device specific. 5 Multiple users may use the same printer; jobs need to be care- fully separated, banner pages provided, and other administra- tive functions performed. 6 Administrators have a strong desire to record the printer usage so that users can be billed appropriately. 7 Some serial line devices must be opened in a nonblocking mode so that configuration operations can be performed. In order to handle printer specific problems, each printer has a set of filters or support programs which provide support for specific operations. For example the of filter will print ban- ners, page separators, and other high level queue control func- tions. Files whose print format is the (lower case) character ? will be printed using a ?f filter; the programs corresponding to each format are found in the printcap file. The algorithm used by LPRng is shown in Figure 8. It is similar to the original Berkeley algorithm, but not identical. Names such as `of' refer to entries in the printcap database and OF is a filter process created from the `of' information; OF = fil- ter('of') -> LP means create the OF filter from the of informa- tion in the printcap file, and send it output to the LP filter or device. While the algorithm used by LPRng is similar to the original Berkeley LPR algorithm, there are some subtle differences. Before the job is printed, it is checked for the formats it uses. If there is no filter available for a data file the job is not LPRng - Introduction 21 printed and only an error message is generated. -//-finish-printing----------------------------------------------- if( OF != LP ) wake up OF filter; if( header last 'hl' && do_banner ){ if( ! no FF separator 'sf' ) 'ff' -> OF; BP = OF; bnr = null; if( banner end program 'be' ) bnr = 'be' else if( banner program 'bp' ) bnr = 'bp' if( bnr ){ BP = filter( bnr ) -> OF; } short banner info -> BP; if( BP != OF ) close( BP ); } if( ff on close 'fq' ) 'ff' -> OF; if( trailer on close 'tr' ) tr -> OF; if( accounting at end 'ae') do accounting; if( OF != LP ) close( OF ); close( LP ); Figure 8c: Printing algorithm used by LPRng 22 LPRng - Introduction The printing device is opened and closed for each print job. This eliminates a set of problems of printer failure; when vari- ous network and other printers will fail printing a file, they will not work correctly until reset by a network reconnection or a device open. In addition, the 'nb' printcap entry forces a nonblocking open to be done on a device. The as and ae printcap entries specify a filter or format to be used to record accounting information at the beginning or end of a job respectively, and the af printcap entry specifies the accounting file where accounting information should be sent. For example, for a 230 byte long job spooled to printer p1 by john on pc1 the entry as=start $P $u $H $b will write start p1 john pc1 230 in the accounting file. The entry as=|/usr/local/psaccnt start will run the psaccnt program, with the additional options specified by the filter_options configuration variable and waits for it to terminate. If the program terminates with a non-zero error status then the job will not be printed. Any error message printed by the program on its stderr output will be placed in the log file. The program stdout will be connected directly to the printer device or filter specified by the lp field. This allows any specialized probing of the printer to be done by the account- ing program. The ae field specifies the string or filter to be used at the end of a job. Similar action is taken at the end of a job using the ae printcap entry. In addition to the accounting done by the lpd program, filters can also do accounting and write their results to the accounting file. By convention, the name of this file will be passed to the filter, and FD 3 will be connected to the file. In addition to these file and program based facilities, if the accounting file has the form af =host%port then it is assumed to specify a host and port for a remote accounting server. The lpd program will make a connection to the specified host and port, and then send the as string (with expanded options) to the LPRng - Introduction 23 server. If the accounting_check flag is TRUE, the server will check for a ACCEPT reply from the server, and will reject the job if it is not received. The connection will be passed to filters as FD 3, and they can also send accounting information to the server. Each site usually has a different set of needs for banner printing. LPRng has removed fancy bannner printing from the lpd server to a separate program. The bp (banner printer) program generates a banner for a job; users can modify the banner without modify the LPRng software. Note that banners can be printed at the beginning and end of jobs. All banner output is passed through the of filter if it is present. LPRng can use vintage filters available for LPR and other spooling systems with a minimum of changes. The section on Fil- ters discusses how they are accommodated. -Filter-specification:-------------------------------------------- path arg1 arg2 $P $w $l $x $y $K $L $c $i \ $Z $C $J $R \ $0n $0h $F $-a Expanded Specification path arg1 arg2 \ -PPrinter -wpw -lpl -xpx -ypy \ -Kcontrolfilename -LLogname -iIndent \ -ZZoptions -CClass -JJobinfo -RRaccountname \ -n Person -h Host -Fformat af Note: pw, pw, etc. are from printcap entries, Printer, Logname, etc. are from control file lines, other information generated by server. Figure 9: Filter Specification and Expansion 24 LPRng - Introduction LPRng supports multiple printers serving a single print queue. The master print queue has a sv=server1,server2,... (servers) printcap entry listing the server printer names; server printers have a corresponding ss=master (serves) printcap entry. The mas- ter spool queue server process creates a subserver process for each slave printer; the subserver processes print all of the jobs in the server spool queue and then terminate. As each of the subservers processes terminates, the master select a job from the master spool queue and then create a new subserver process. This subserver process will copy the job to the server spool queue and then process the job. Note that print jobs can be directly spooled to slave spool queues, allowing users to send jobs to a server printer as well as to the master spool queue. Filters The LPRng software makes heavy use of filter processes for printing and other operations. A filter specification has the form | [-$] path optionsP Printcap printer filter entries usually drop the `|' filter indi- cation. Filters run with EUID and RUID daemon; the ROOT keyword runs EUID ROOT. See Security Considerations for details. The path entry specifies the absolute pathname of an exe- cutable file and the options are a set of options to invoke the filter with. In addition to the user specified options, the LPRng software will append the configuration variable fil- ter_options unless suppressed by the -$ flag. The options are scanned for variable substitutions indicated by $ characters, followed by zero or more of the format indica- tion characters ' (single quote), - (minus), or 0 (zero). If key has a non-zero length string value X, then $key expands to -key'X'; the 0 format key add as space between the key letter and the value, ' suppresses quotation marks, and - suppresses the key flag. $0key expands to -key 'X' $-key expands to 'X' $'key expands to -key X $-'key expands to X LPRng - Introduction 25 The $c key should be used only for printing filters. If the data file format is l (i.e.- binary) $c expands -c otherwise it is the empty string and does not appear in the output. The following is a list of keys and their corresponding values (:x: indicates a printcap value, control file is a line from the job control file). Key Source Value a :af: accounting file b data file data file size c control file data file format (see above). d LPD control directory e LPD pathname of data file in spool queue f control file data file original file name h control file short form of originating host name i control file indent specified to LPR j control file job number l :pl: page length m :cf: page cost factor for accounting n control file user name s :ps: printer status file t LPD current time w :pw: page width x :px: page x dimension F data file format P LPD printer name S :cm: comment tag Upper Case Character control file Corresponding control file field If there is no corresponding value for any of these keys, the result is a null (empty) string. The substitution formats allow the user to create interfaces to vintage printer filters with a minimum of effort; see below for an example. As a further aid, The printcap bkf (backwards filter) flag appends a list of options which are compatible with most vintage printer filters. The environment variables for filters are highly restricted, due to the possibility for abuse by users. The following vari- ables are set: USER and LOGNAME user name or daemon name. LOGDIR home directory of user or daemon. PATH from the filter_path configuration variable. LD_LIBRARY_PATH from the filter_ld_path configuration variable. SHELL set to /bin/sh IFS set to blank and tab. TZ the TZ environment variable. SPOOL_DIR the spool directory for the printer CONTROL_DIR the control directory for the printer PRINTCAP the printcap entry for the printer CONTROL the control file for the print job pass_env environment variables Values of environment variables listed in the pass_env configuration variable. The LPRng software provides several methods of performing accounting. 26 LPRng - Introduction The printcap af (accounting field), as and ae (accounting start and end), and achk (accounting check) provide a basic set of facilities. The af field specifies a file, filter, or TCP net- work connection to an accounting server. If af has the form |filter or |-$ filter then a filter will be started and all accounting information will be sent to the filter. The first form passes the filter the command line options specified by the filter_options configuration variable and the second suppresses option passing. If af has the form host%port then a TCP connec- tion will be opened to the port on the specified host and accounting information sent there. All other forms will be treated as a pathname relative to the queue spool directory. When af specifies a filter or network connection and the achk flag is set, then after writting the initial accounting informa- tion (see as printcap field below) the server will wait for a reply of the form ACCEPT from the filter or server. If not received, the job will not be printed. The as (accounting start) and ae (accounting end) fields can specify a string to be printed or a filter. Options in the string will be expanded as for filters, and the strings printed to either the accounting information destination. If the as field specifies a filter, then the print server will wait for the filter to exit before printing the job. If the exit status is 0 (successful), the job will be printed. A non-zero JREMOVE status will remove the job, while any other status will terminate queue printing operations. After printing the job, the ae filter will be started and the server will wait for it to complete before printing the next job. The as and ae filters will have STDOUT set to the printing device and or filter, and the STDERR set to the error log file for the print queue, and fild descriptor 3 set to the destination specified by the af field. As a convenience, all format filters for printing will be started with file descriptor 3 set to the destination (file or filter) specified by the printcap af field. This allows special filters which can query devices for page counts to pass their information directly to an accounting program. The descriptor will READ/WRITE, allowing filters to query the accounting program and/or update the information directly. By convention filters read input from stdin, write to stdout, and write errors to stderr. The error output is usually directed to the error logging file for the printer. Print filters have their current directory set to the printer spool directory. Security Considerations Security considerations were a major factor in the design of the LPRng software. Many of the problems center on the following issues. 1. Users trying to use the printer spooler software to exploit bugs in the operating system and gain root access. 2. Users trying to use the printer spooler software to gain unauthorized access to other users files, 3. Users trying to gain illegal access to printing facilities. 4. Users trying to avoid accounting procedures. LPRng - Introduction 27 5. Denial of service attacks. The first issue to be dealt with is the problem of ROOT per- missions. All of the client LPRng programs can run as ordinary users; this eliminates a large number of attacks on system secu- rity by trying to exploit various defects in the system based on SUID root programs. The LPD server is the only program that absolutely needs to run with real UID (RUID) ROOT as it uses a privileged TCP/IP port to listen for incoming connections, and in most UNIX systems bind(2) requires EUID ROOT permissions to bind to a privileged port. (It is not recommended that a non-privi- leged port be used as a trojan horse user program can bind to it and impersonate the LPRng software.) According to RFC1179 a con- nection to a server must originate from a (privileged) port in the range 721-731. Given this need for ROOT permissions, the LPRng code goes to extreme lengths to ensure that only the bind(2) calls are made with EUID root, and that all other operations are done either as daemon (server) or as user (clients). It is strongly recommended that the lpd program not be SUID root, but should started up by the system initialization rc(4) scripts or a root user. It is recommended that all client programs be run as user (non privileged) jobs. Only files accessible to the user will be read or transferred to the server. If a user wants to access a printer that requires privileged ports, it is a simple matter to create a bounce queue on a server that will forward a job to the remote system. The checkpc (check printcap) program scans the printcap and permissions databases, spool queues, and checks permissions of files and directories. If run by ROOT with the -f (fix) flag set, it will try to change ownerships, create files and/or direc- tories, and remove junk or old job files from spool queues. This program also has some portability tests built into it, and can be used to check that the target system can safely run the LPRng software. Most efforts to circumvent accounting and permissions checks are based on forging or impersonation of another user or network host. The current version of the LPRng software depends on the various system configuration and database utilities to provide user authentication and system authentication. This is clearly inadequate, and LPRng support encryption based authentication; support for using Kerberos (version 5) is built into the system. PGP and other forms of authentication are supported by using the filter mechanism to invoke a set of authentication programs rather than directly incorporating the code into the LPRng soft- ware. Details of the exact interface for authentication can be found in the lpd(8) man page documentation. One of the arguments for running client programs SUID ROOT is that it allows them to connect to the server from a privileged port, and the information provided will be authenticated in some manner by use of the operating system facilities. Unfortunately, the LPRng software uses various network databases to obtain con- necting host information; by attacking the the system by spoofing database (DNS) server activities, it is possible to forge authen- tication. 28 LPRng - Introduction The use of NFS exported and mounted spool directories exposes the LPRng software to extreme attack. One of the assumptions made by most spooling systems is that only the trusted spooling software or trusted application programs will have write access to the spool directory; when the directory is NFS mounted or exported this may no longer be true. Several spooling systems operate by writing job control and data files into an NFS mounted spool directory. By appropriately forging network identifica- tion, credentials, and various RPC calls, attackers can create or modify unprotected files in the spooling directory. The ability to read information in job or other files may also give them the ability to launch other forms of attack. One of the more mali- cious denial of service attacks is to create a file that cannot be removed or modified; the spooler software may end up repeat- edly attempting to print the file, blocking other users from using the spool queue and consuming printer resources. In order to protect the LPRng software from NFS spoofing based attacks, the printcap cd=directory entry specifies a separate control file directory to be used by lpd for all spool queue files except the job and data files. This directory should not be NFS mounted or exported, and should reside on the local host file system. This directory should be carefully created so as to be accessible only by user daemon. Printcap and other informa- tion can be safely placed in this directory as it cannot be modi- fied by NFS operations. Avoiding printing accounting procedures has long been a tradi- tion at educational institutions; while minor infringements are usually ignored, persistent and blatant offenses are worrisome. In addition, once an individual discovers a method then it appar- ently is rapidly copied by others, leading to widespread abuse. One difficulty faced by administrators is determining the resources used by a job. As part of the printing algorithm, the LPRng software provides a set of hooks to allow the invocation of accounting programs before and after the actual job is printed. For example, most PostScript printers have a page count register whose value can be easily read by a simple Postscript Program. By reading this before and after a job the total usage can be calculated. However, some students have discovered that by aborting a job in the middle of its printing or by printing a job that contains information that causes the printer to hang and not report the total pages used at the end of a job they can avoid the normal accounting procedures. By recording information before as well as after a job completes such incomplete jobs can be found. Filters are a major security loophole, as most filters are shell scripts and inherit shell script vulnerabilities. To com- bat this, the LPRng software defaults to running all filters either as the user or as daemon, and provides a predefined and limited set of environment variables. Some network printer fil- ters need to open a privileged port and must have root permis- sions. This is a serious vulnerability, and the lp=host%port printer specification has been provided to ameliorate this prob- lem. It has been recommended that filters run as user nobody, restricting capabilities to an even greater exent, and this LPRng - Introduction 29 consideration is under study. If it is absolutely necessary that a filter execute with ROOT permissions, then the adminstrator should install the filter SUID root, but only allowing execution by group daemon. For example: chown root $filter chgrp daemon $filter chmod 4010 $filter Filters which are actually shell scripts are vulnerable to attacks using metacharacters in option strings. To combat this, the LPRng software ruthlessly purges all non-alphanumberic, whitespace and simple punctuation (minus, equal, period, slash, and comma) characters from filter options. The raw option infor- mation is available in the PRINTCAP and CONTROL_FILE environment variables. Administrators would be wise to examine shell based printer filters for similar security loopholes. Deliberate denial of service attacks are almost impossible to avoid. However, heavy usage of the printer system can produce almost the same symptoms. For example, when a large number of print jobs are queued it is possible to exhaust the spool queue file space. The printcap mx (maximum job size) entry specifies the maximum job size (in Kbytes) to be queued and the mi (minimum free space) entry specifies the minimum free space (in Kbytes) needed. Example Printcap Files The following is a typical set of LPRng printcap files that could be used With the psfilter programs. We assume we are talking to a HP IV printer, ecepr3, it us using a Jetdirect card which allows a direct printer connection on port 9100. We have installed the filter software as follows: /usr/local/lib/ - directory psif - IF filter psof - OF filter bannerx - banner printer Version 1: by default, the psof filter will print a banner using information on the short banner line and/or parameters passed by LPRng. # LPRng printcap files # HP LaserJet 4m+ lw4|lp|HP LaserJet 4M # job size information :mx#0 # spool directory :sd=/usr/spool/cca_4mp: # device network address :lp=ecepr3%9100 :rw # set up status and # accounting files :sf=status :af=acct :lf=log # page information size :pl#60:pw#80: 30 LPRng - Introduction # you need SHORT BANNER # specify the SHORT BANNER # line format :sb :bl=Seq\: $-'j \ Class\: \ $-'C \ User\: $-'n Job\: $-'J \ Date\: $-'t # turn FF off :sf # filters :if=/usr/local/lib/psif :of=/usr/local/lib/psof Version 2: You want to have a special banner, so you specify a BP banner printers explicitly and turn of the psof banner generation. Make the following changes to Version 1. REMOVE: :sb (you want full banners) ADD: # use new banner printer :bp=/usr/local/lib/bannerx CHANGE # pass option to filter to # turn of banner generation and # pass through text :of=/usr/local/lib/psof -Tbanner=off Version 3: Printer is on /dev/ttya serial line. Note: the stty options are taken from an actual functioning printer connection and should work for HP printer on a serial line). Make the following changes to Version 1. CHANGE: :lp=/dev/ttya ADD: :sy=38400 -echo -crmod \ -raw -oddp -evenp \ pass8 cbreak ixon Version 4: you do not want banner pages at all. Make the follow- ing changes to Version 1. # LPRng printcap files ADD: # suppress all header info :sh Summary and Acknowledgments The LPRng software continues to evolve as users find problems and develop new printing requirements. One of the areas to be pursued is the use of encryption for end to end authentication of users and print jobs. Another is adding interfaces to other net- work based spooling systems. Finally, documentation and auto- mated management continues to be pursued. The network based interfaces for client programs makes user developed GUI systems almost trivial to develop. PERL scripts LPRng - Introduction 31 and Tkl/Tk based front ends can be developed rapidly and with little effort. The development of the PLP and LPRng software would not have been possible without the aid and assistance of literally hun- dreds of users. The main developer of the software was Patrick Powell , and Justin Mason generated the PLP4.0 distribution, contributed much of the porta- bility code, and organized the plp@iona.ie mailing list. Sub- scribe by sending email to plp-request@ iona.ie with the word subscribe in the body. Marty Leisner , Ken Lalonde , and Michael Joosten performed invaluable portability testing and debugging of the LPRng Alpha Minus release; they discovered and provided fixes for literally hun- dreds of bugs. LPRng was based on PLP Release 4.0, to which the following people (in alphabetical order) contributed: Alan F Lundin Alan Shutko Andrew Leahy , Andrew Richards Angus Duggan Avery Earle Baba Z Buehler Bertrand Decouty-INRIA Rennes-France Bertrand Wallrich Bjarne Steinsbo Brad Greer Carl Hilton Chao-Wen Young Corey Minyard Dave Alden David M Clarke Desmond Macauley Dirk Wrocklage Dorab Patel Doug White , Dwaine C. Gonyier Ed Santiago Elliot Lee Eric C Hagberg Geoff Ballinger George Harrach George Lindholm Greg Wohletz Harlan Stenn Helmut Jarausch Hendrik Klompmaker Jan Barte Jarrod Douglas Jens Thiel Jon E. Ferguson Jos Backus Julian Anderson 32 LPRng - Introduction Julian Turnbull Klaus Steinberger Lothar Butsch Marc Baudoin Martin Forssen Marty Leisner Michael Haardt Michael Joosten Michel Robitaille Ole Benner Panos Dimakopoulos Paul Burry Paul Eggert Paul Haldane Per Foreby QingLong Rick Martin Ron Roskens Scott Sutherland Sherwood Botsford Stefan Monnier Stefano Ianigro Stuart Kemp Sven Rudolph Todd C. Miller Zygo Blaxell Author Information Patrick Powell is the CEO of Astart Technologies in San Diego, a consulting firm specializing in net- work and system management. References Pow96. Patrick A. Powell, LPRng Version 3.1 - README and MAN Pages, Dept. of Electrical and Computer Engineering, San Diego State University, San Diego, CA 92182, 1997. FTP://ftp.iona.ie /pub/LPRng/, FTP:// ftp.astart.com /pub/LPRng/ Pow95. Patrick A. Powell, LPRng - Introduction and Reference Man- ual, Dept. of Electrical and Computer Engineering, San Diego State University, San Diego, CA 92182, 1995. FTP://ftp.iona.ie /pub/LPRng/, FTP:// ftp.astart.com /pub/LPRng/ Cam94. Ralph Campbell, ``4.3BSD Line Printer Spooler Manual,'' 4.4 Berkeley Software Distribution, Computer Systems Research Group, U.C. Berkeley, Berkeley CA, 1994. USENIX Association and O'Reilly & Associates, Inc. Pow95a. Patrick A. Powell, ``PLP - The Public Line Printer Spooler Reference Manual,'' PLP 4.0 Software Distribution, 1995. FTP://ftp. iona.ie/pub/plp-4.0 McL90. Leo J. McLaughlin III, RFC1179 Line Printer Daemon Proto- col, Internet Advisory Board, 1990. GNU91. GNU, GNU General Public License, Free Software Foundation, Inc., 675 Mass. Ave. Cambridge, MA 02139, 1991. LPRng - Introduction 33 34 LPRng - Introduction