LPRng-HOWTO Patrick Powell papowell@astart.com 21 Dec 1998 (For LPRng-3.5.4) The LPRng software is an enhanced, extended, and portable implementa- tion of the Berkeley LPR print spooler functionality. While providing the same interface and meeting RFC1179 requirements, the implementa- tion is completely new and provides support for the following fea- tures: lightweight (no databases needed) lpr, lpc, and lprm programs; dynamic redirection of print queues; automatic job holding; highly verbose diagnostics; multiple printers serving a single queue; client programs do not need to run SUID root; greatly enhanced security checks; and a greatly improved permission and authorization mechanism. The source software compiles and runs on a wide variety of UNIX sys- tems, and is compatible with other print spoolers and network printers that use the LPR interface and meet RFC1179 requirements. The package comes with filters for PostScript and HP printers, as well as the usual 'dumb' printers. Note that the PostScript and HP filters do page counting and produce accounting information accounting. In addition, there are a wide variety of other filters that can do page formatting, and produce banner pages. For users that require compatibility with the SVR4 lp and lpstat interface, lpr and lpq will simulate this interface, eliminating the need for another print spooler package. In addition, a publically available PCNFSD server is distributed with LPRng, and interfaces with the PC/DOS/Windows based NFS style print spoolers. For users that require secure and/or authenticated printing support, LPRng supports Kerberos 5, MIT Kerberos 4 extensions to LPR, and PGP authentication methods. Additional authentication support is extremely simple to add. ______________________________________________________________________ Table of Contents 1. Introduction 1.1 What is LPRng? 1.2 More Information 1.3 Copyright 1.4 Disclaimer 1.5 Commercial Support 1.6 Web Site 1.7 FTP Sites 1.8 Mailing List 1.9 PGP Public Key 2. The Most Frequently Asked Questions 2.1 Why do I get malformed from address errors? 2.2 It was working normally, then I get connection refused errors 2.3 Job is not in print queue, but it gets printed! 2.4 Job disappears and is never printed, but lpr works 2.5 I get messages about bad control file format 2.6 What is RFC 1179, the Line Printer Daemon Protocol? 2.7 I want to replace lp, lpstat, etc, but my programs need them 2.8 What are the drawbacks to LPRng? 3. Installing your printer 3.1 Parallel Printers 3.2 Serial Printers 3.2.1 Converting BSD 3.3 Network Printers 4. Installing the programs 4.1 Files and Setup 4.2 Source Code and Installation 4.2.1 Building the software 4.2.2 Problems with compilation 4.3 Preparing to run the daemon 4.3.1 Removing Existing Facilities 4.3.2 Startup Scripts 4.4 Replacing UNIX SystemV lp, lpstat Printing Services 4.5 Setuid ROOT and Security Issues 4.6 System specific notes 4.7 Solaris 2.4, 2.5, 2.6 4.8 Solaris, Newsprint and FrameMaker 4.9 Linux 4.10 AIX 4.11 Appletalk Support 4.12 Apple to LPRng Printing 4.13 LPRng to Appletalk Printing 4.14 SAMBA Support 4.14.1 What is SMB 4.14.2 Samba and LPRng 4.15 Printer Specific notes 4.16 HP Deskjet 4.17 HP LaserJet IIISiMX 4.18 HP Deskjet 1600CM 4.19 HP JetDirect Interface 4.19.1 Setting Up IP Networking and Address 4.19.2 BOOTP Information 4.19.3 Paper Tray Selection 4.20 Lexmark Printers 4.21 Tektronix P450 and Family 4.22 Duplex Printing 4.23 Test Version and Portability Testing 4.23.1 Compiling the Test Version 4.23.2 Setting Up The Test Version Spool Queues 4.23.3 Running the Test Version Software 4.23.4 Portability Testing 5. /etc/printcap Print Spool Database File 5.1 Index To All The Options 5.2 A very simple example 5.3 A serial printer queue 5.4 A remote printer queue 5.5 Network Printing With /etc/printcap 5.6 Spooling To Local Server 5.7 Shared printcap files 5.8 Master Printcap Files 5.9 Printcap options for lpr, lpq, lprm, and lpc 5.9.1 lp, rm and rp 5.10 Bounce queues 5.11 LPR Filtering 5.12 Dynamic Routing 5.13 Support for Network Print Servers 5.14 Printer load balancing 5.14.1 Multi-server print queue 5.14.2 Checking Busy Status of Server Queues 5.14.3 Using a router filter 5.15 The Missing Details 5.15.1 Spool (Control) Directory Printcap File 5.15.2 Separate Printcap Files for LPD 5.15.3 Printcap Entry all 5.15.4 More Example Printcap Entries 5.15.5 PC-NFS Print Spooler 5.16 Management Strategy for Large Sites 5.17 Using Programs To Get Printcap Information 5.17.1 How to use NIS and LPRng 5.17.2 How to use NIS and LPRng - Sven Rudolph 5.18 The Record Queue Name qq and force_queuename flags 5.19 Using the check_for_nonprintable Flag 5.20 The fd Forwarding Off Option 5.21 The rg Restrict Use to Group Members Option 5.22 The fx Allowed Formats Option 5.23 Fixing Bad Control Files and Metacharacters 5.23.1 Defective RFC1179 Implementations 5.23.2 OS/2 5.23.3 Serious Security Loophole 5.23.4 Fixing Bad Jobs 5.23.5 Using the bk Option and Control File Filters 5.24 Maximum Copies 5.25 The minfree Minimum Spool Queue Space Option 5.26 Debugging 5.27 LPD Specific 5.28 Legacy Compatibility 5.28.1 The allow_duplicate_args Option 5.28.2 The class_in_status Options 5.28.3 The reverse_lpq_format Option 5.28.4 The return_short_status and short_status_length Options 5.28.5 The force_lpq_status Options 5.28.6 The ignore_requested_user_priority and force_fqdn_host Options 5.28.7 The lpr_bsd Options 5.29 Compatibility with BSD printcap 6. Filters 6.1 What are filters? 6.2 What are print formats? 6.3 OF Filter 6.3.1 The filter_poll Option 6.4 The lpr -p format and pr option 6.5 The lpr -l format and binary format 6.6 Job Processing and Printcap Options 6.6.1 Opening the Output Device 6.6.2 Printing Banner At Beginning 6.6.3 Printing Job Files 6.6.4 Printing Banner At End 6.6.5 Normal Termination 6.6.6 Abnormal Termination 6.6.7 LPD Spool Queue Processing 6.7 Filter Command Line Flags 6.8 Bounce queues and filters: caveats 6.9 The lpr -p format and :pr filter 6.10 Changing Filter Formats 6.11 LPRng Supported Filters 6.11.1 Filter Distribution Conventions 6.11.2 lpf 6.12 IFHP Filter 6.12.1 Printer Capabilities 6.12.2 hpif Options 6.12.3 Parallel Port Printer 6.12.4 Printing Banners 6.12.5 Error Logging 6.12.6 Accounting Information 6.12.7 Accounting 6.13 lp_pipe Filters 6.14 apsfilter Filter 6.15 Using your own filters 7. Spool Queues and Files 7.1 Spool Queue and Control Queue 7.2 Job State 7.3 Printer Lock File 7.4 Spool Control File 7.5 Log and Status Files 7.6 Job Control File 7.7 Job Hold File 7.8 Job Identifier 8. /etc/lpd.conf Configuration File 8.1 Configuration File Format 8.2 Obtaining Configuration Information 8.3 Useful Configuration Options 8.3.1 default_format 8.3.2 default_permission=ACCEPT 8.3.3 default_priority=A 8.3.4 default_remote_host=localhost 8.3.5 default_tmp_dir=/tmp 8.3.6 domain_name=domain.name 9. The /etc/lpd.perms Permissions File 9.1 Information for matching 9.2 Permission Checks 9.3 Match Procedure 9.3.1 DEFAULT 9.3.2 SERVICE 9.3.3 USER 9.3.4 REMOTEUSER 9.3.5 HOST 9.3.6 REMOTEHOST 9.3.7 PORT 9.3.8 IP 9.3.9 REMOTEIP 9.3.10 LPC 9.3.11 SAMEUSER 9.3.12 SAMEHOST 9.3.13 SERVER 9.3.14 FORWARD 9.3.15 GROUP 9.3.16 REMOTEGROUP 9.3.17 CONTROLLINE 9.3.18 AUTH 9.3.19 AUTHUSER 9.3.20 FWDUSER 9.3.21 IFIP 9.4 Permission File Location 9.5 Example Permission File 9.6 Complex Permission Checking 9.7 More Examples 10. Running the software 10.1 LPRng's little helper: checkpc 10.2 Starting the daemon 11. Accounting 11.1 Printer Accounting Reality Check 11.2 How HP Printers Implement Page Counters 11.3 Accounting Printcap Options 11.4 Accounting File 11.5 Remote Server Accounting 11.6 Using Filters For Accounting 11.7 Accounting Utility accounting.pl 12. Authentication and Encryption 12.1 Authentication 12.2 Identifiers 12.3 RFC1179 Protocol Extensions 12.4 Client Operations for Client To lpd Server Authentication 12.5 Server Operations for Client To lpd Server Authentication 12.6 lpd Server to Server Authentication 12.7 Permission Checking 12.8 Using PGP for Authentication 12.8.1 PGP Configuration 12.8.2 Permissions 12.8.3 Client Configuration 12.9 Using Kerberos 5 for Authentication 12.9.1 Kerberos Installation Procedure 12.9.2 Testing Transfers 12.9.3 Explicit Server Principal Name 12.10 Using Kerberos 4 for Authentication 13. Status Monitoring and Logging 13.1 LPQ status reporting 13.2 LPQ Short Format (lpq -s) 13.3 LPQ Long Format (lpq default, lpq -l, lpq -L) 13.4 LPQ Verbose Format (lpq -v) 13.5 lpc status 13.6 Remote Logger Operation 13.6.1 Logger Network Communication 13.6.2 Logger Messages 13.6.3 Message Format 13.6.4 Dump Messages 13.6.5 LPD Messages 13.6.6 Job Status Messages - UPDATE 13.6.7 Printer Status Messages - PRSTATUS 13.7 LPR -mhost%port and user logging support 14. RFC 1179 - Line Printer Daemon Protocol 14.1 Ports and Connections 14.2 Protocol Requests and Replies 14.3 Job Transfer 14.4 Data File Transfer 14.5 Control File Contents 14.6 LPQ Requests 14.7 LPRM Requests 14.8 LPC Requests 14.9 Block Job Transfer 14.10 Authenticated Transfer 15. Acknowledgements ______________________________________________________________________ 11.. IInnttrroodduuccttiioonn This document is an attempt to provide some simple guidelines to set up LPRng. It is aimed at system managers who want to replace their vendor's printer daemon and its clients by LPRng. LPRng can be configured in many ways, making it suitable for a broad range of applications. It has a large amount of options which are explained in the extensive documentation. Despite (or due to) the extent of the documenting files, many new users experience problems in setting up the package. One of the reasons is that most of the LPRng documentation assumed that you already have a working knowledge of a BSD-style printer spooler. In this document, I will first try to give some simple guidelines that should enable you to put together a simple working configuration without being overwhelmed by options. Next, there are some detailed descriptions of the way that LPRng does things. Finally, there are detailed discussions about various LPRng facilities that try to encapsulate common configurations and operations that administrators and users encounter. 11..11.. WWhhaatt iiss LLPPRRnngg?? Gordon Haverland (haverlan@agric.gov.ab.ca) put it this way: LPRng is a print spooling system. It was designed to mimic the Berkeley (University of California - Berkeley) Line Printers (LPR) package, first found on Berkeley derivatives of the Unix operating system. The LPRng package supports users being able to print a document with little or no knowledge of the content or special processing required to print the document; on a stand-alone machine, on a LAN, or remotely. New (as compared to Berkeley LPR) features include: lightweight lpr, lpc and lprm programs; dynamic redirection of print queues; automatic job holding; highly verbose diagnostics; multiple printers per queue; and enhanced security (SUID not required in most environments), improved file permissions, authorization checks, ...), etc. Patrick Powell (), the author of LPRng, has the following comments: LPRng started life in 1986 as PLP (Public Line Printer), a replacement for the original BSD LPD code. This was a one- shot effort to develop code that could be freely redistributed without the restrictions of the BSD/AT&T license, and would allow non-license sites to fix and patch problems that they were having with print spooling. (This was before the Free Software Foundation.) From 1988 to 1992, various groups added features, hacked, and modified the PLP code, coordinated largely by Justin Mason (), who also started and sponsors the LPRng mailing list (see below). In 1992, I redesigned and reimplemented the PLP code and named the result LPRng. The goals of the LPRng project were to build a server system that was as close to user abuse proof as possible, that would provide services limited only by the inherent capacities of the support system, RFC1179 compliant, and with extensive debugging capabilities to allow quick and easy diagnostics of problems. Over the period from 1994-1997, LPRng users have suggested extensions, provided patches, and added facilities. I have tried to incorporate these in a controlled and cautious manner. As a side effect of this work, many security problems that could develop were identified and steps taken to ensure that they were not present in LPRng. For example, if you want, you can run LPRng clients such as lpr, lprm, lpc, and lpq as a non-privileged user; this reduces the chances of users exploiting faults in the code and gaining root privileges. Bounds checking is performed on all input and formatting (for example, snprintf() rather than sprintf() is used), as well as other preventive measures where appropriate. In most cases, LPRng is nnoott a drop-in replacement for BSD LPR. For most installations, you will need adaptations. However, most of the changes are minor, and many of the LPRng facilities are backwards compatible with existing BSD print spooler facilities. 11..22.. MMoorree IInnffoorrmmaattiioonn Much of the material in the LPRng documentation has been included in this document. For example, previous releases of LPRng had a large selection of README files; most of these are now incorporated into the HOWTO document. Current information about LPRng and the latest release can be found on the LPRng web page: http://www.astart.com/LPRng.html There is also a mailing list at lprng@iona.com. To subscribe, send an email to lprng-request@iona.com. The body should contain only the word `subscribe'. To get off the list later on, repeat the same procedure, but use the word `unsubscribe'. Several presentations of LPRng and print spooling software have been made at the Large Scale Installation Administrator (LISA) conferences and are in the LPRng distribution and available on web sites. LPRng - An Enhanced Printer Spooler System was presented at the LISA95 conference, and is in the LPRng distribution as LPRng_DOC/LPRng- LISA95.ps. On a more general topic, the slides for the LISA97 tutorial on Printers and Network Print Spooling are also in the LPRng distribution in the LPRng_DOC/LISA97 directory. The LPRng distribution also has a set of man pages (in the man/ directory) that are the reference for the LPRng operation. When in doubt, please consult them. 11..33.. CCooppyyrriigghhtt Material included in this document from the LPRng distribution Copyright Patrick Powell 1988-1997, where applicable. The rights to distribute this document complete or in part are hereby granted for non-commercial purposes. Partial reproductions must acknowledge the source. Permission to distribute this file together with LPRng and `derived works' (as defined in the LPRng license) is explicitly granted. This is allowed independent of the license under which the software is distributed. Citing the document is allowed as long as the source is acknowledged. 11..44.. DDiissccllaaiimmeerr TTHHEE MMAATTEERRIIAALL IINN TTHHIISS HHOOWWTTOO IISS PPRROOVVIIDDEEDD WWIITTHHOOUUTT FFEEEE AANNDD AASS--IISS WWIITTHH NNOO WWAARRRRAANNTTYY RREEGGAARRDDIINNGG FFIITTNNEESSSS OOFF UUSSEE FFOORR AANNYY PPUURRPPOOSSEE.. TTHHEE AAUUTTHHOORR AANNDD AALLLL CCOONNTTRRIIBBUUTTOORRSS AARREE NNOOTT LLIIAABBLLEE FFOORR AANNYY DDAAMMAAGGEESS,, DDIIRREECCTT OORR IINNDDIIRREECCTT,, RREESSUULLTTIINNGG FFRROOMM TTHHEE UUSSEE OOFF IINNFFOORRMMAATTIIOONN PPRROOVVIIDDEEDD IINN TTHHIISS DDOOCCUUMMEENNTT.. 11..55.. CCoommmmeerrcciiaall SSuuppppoorrtt AStArt Technologies provides commercial support and enhancements for the LPRng and other network software. AStArt provides network and system consulting services for UNIX and NT systems, as well as real time and network software. 11..66.. WWeebb SSiittee Web Page: http://www.astart.com/lprng.html 11..77.. FFTTPP SSiitteess The software may be obtained from ftp://ftp.astart.com/pub/LPRng(Main site) Mirrors: ftp://ftp.sage-au.org.au/pub/printing/spooler/lprng (AU) ftp://sunsite.ualberta.ca/pub/Mirror/LPRng/ (CA) ftp://ftp.informatik.uni-hamburg.de/pub/os/unix/utils/LPRng (DE) ftp://ftp.uni-paderborn.de/pub/unix/printer/plp/LPRng (DE) ftp://ftp.iona.ie/pub/plp/LPRng (IE) ftp://ftp.chembio.ntnu.no/pub/mirrors/LPRng (NO) ftp://ftp.mono.org/pub/LPRng (UK) ftp://ftp.cs.columbia.edu/pub/archives/pkg/LPRng (US) ftp://ftp.cs.umn.edu/pub/LPRng (US) ftp://ftp.iona.com/pub/plp/LPRng (US) ftp://uiarchive.uiuc.edu/pub/packages/LPRng (US) 11..88.. MMaaiilliinngg LLiisstt To join the LPRng mailing list, please send mail to lprng- request@iona.ie with the word 'subscribe' in the BODY. The LPRng mailing list is archived on http://www.findmail.com/list/lprng 11..99.. PPGGPP PPuubblliicc KKeeyy The LPRng distributions have an MD5 checksum calculated, which is then signed with a PGP public key. Here is the key for validating the checksums: Type Bits/KeyID Date User ID pub 1024/00D95C9D 1997/01/31 Patrick A. Powell Patrick A. Powell -----BEGIN PGP PUBLIC KEY BLOCK----- Version: 2.6.3i mQCNAzLygTQAAAEEANBW5fPYjN3wSAnP9xWOUc3CvsMUxjip0cN2sY5qrdoJyIhn qbAspBopR+tGQfyp5T7C21yfWRRnfXmoJ3FVtgToAsJUYmzoSFY08eDx+rmSqCLe rdJjX8aG8jVXpGipEo9U4QsUK+OKzx3/y/OaK4cizoWqKvy1l4lEzDsA2VydAAUT tCdQYXRyaWNrIEEuIFBvd2VsbCA8cGFwb3dlbGxAYXN0YXJ0LmNvbT6JAJUDBRA0 XonoiUTMOwDZXJ0BAQ2cBAC7zU9Fn3sC3x0USJ+3vjhg/qA+Gjb5Fi1dJd4solc4 vJvtf0UL/1/rGipbR+A0XHpHzJUMP9ZfJzKZjaK/d0ZBNlS3i+JnypypeQiAqo9t FV0OyUCwDfWybgAORuAa2V6UJnAhvj/7TpxMmCApolaIb4yFyKunHa8aBxN+17Ro rrQlUGF0cmljayBBLiBQb3dlbGwgPHBhcG93ZWxsQHNkc3UuZWR1PokAlQMFEDLy gTSJRMw7ANlcnQEBYBYD/0zTeoiDNnI+NjaIei6+6z6oakqO70qFVx0FG3aP3kRH WlDhdtFaAuaMRh+RItHfFfcHhw5K7jiJdgKiTgGfj5Vt3OdHYkeeh/sddqgf9YnS tpj0u5NfrotPTUw39n6YTgS5/aW0PQfO9dx7jVUcGeod1TGXTe9mIhDMwDJI4J14 =3Zbp -----END PGP PUBLIC KEY BLOCK----- 22.. TThhee MMoosstt FFrreeqquueennttllyy AAsskkeedd QQuueessttiioonnss In this section, the Most Frequently Asked Questions have been placed, together with their answers. You may notice that some questions have the same answer, but the symptoms appear differently. Some of these answers will reference other material in this FAQ, or the LPRng man pages. 22..11.. WWhhyy ddoo II ggeett mmaallffoorrmmeedd ffrroomm aaddddrreessss eerrrroorrss?? This is the number one question asked by most LPRng users who try to use LPRng with network printers or other systems supporting ``RFC1179'' printing. For details about LPRng and RFC1179, see ``RFC1179 and LPRng''. The malformed from address error is usually reported when trying to send a print job from LPRng to other BSD LPR or RFC1179 LPR implementations, or with network connected printers that have a built in LPR server. This is due to the following RFC1179 rule: Servers originate a connection from ports in the range 721-731. WHY? These are a subset of the 'reserved' ports in UNIX, and normal users cannot open connections from them. This provides a small amount of security from UNIX users on the host 'spoofing' a server. IMPLICATION: in order to do use a reserved port, the program must have root privileges. This means the LPR, LPD, LPQ, etc., programs must be installed SUID root. This can open up a can of worms with regard to security, but LPRng has been designed to take as much paranoid care as possible to avoid problems. WHAT TO DO: When installing LPRng, you will need to install the executables SUID root. In the src/Makefile, you can remove the comment from the line PERMS=SUID_ROOT_PERMS and then do make install. This will install the executables SUID, and owned by root. 22..22.. IItt wwaass wwoorrkkiinngg nnoorrmmaallllyy,, tthheenn II ggeett ccoonnnneeccttiioonn rreeffuusseedd eerrrroorrss This message usually appears when you have been sending a large number of jobs to a network printer or a remote system. The reason for this is a combination the above port 721-731 restriction and the TCP/IP timeouts. For details, see ``RFC1179 and LPRng'', but here is a quick explanation. A TCP/IP connection is usually specified as between srchost:srcport, desthost:destport, although in practice the order of source (src) and destination (dest) is not important. When a connection is established, each end of the connection exchanges the necessary flow control and error control information. When a connection is terminated, each end of the connection will not accept another connection from the same host:port that was previously active for a specified timeout period, usually 10 minutes. Some TCP/IP implementations go further: they will not allow AANNYY connection to be oorriiggiinnaatteedd (via the bind() system call or API) from a port that was active, or accepted on a port that was active for this timeout period. Now let us see what happens when we have a client program, which must originate a connection on port 721-731, connect to the server, which waits for a connection on port 515. We first try to make a connection from host:port 1.1.1.1:721 to 1.1.1.2:515. The first time that we make the connection (or the first connection) we succeed. We can transfer a file, etc., and then close the connection. When we try to reconnect from 1.1.1.1:721 to 1.1.1.2:515 we get an error such as "address already in use" or "connection refused". Luckily, we can use port 722 to originate a connection, and we can connect from 1.1.1.1:722 to 1.1.1.2:515. We continue on, until we come to port 731, and then we need to wait for our timeouts. SOLUTION: It appears that most RFC1179 implementations do not check for the exact port range 721-731, but only that the connection originates from a reserved port, i.e. - in the range 1-1023. You can extend the range of ports used by LPRng by changing the originate_port=721 731 value in the defaults (LPRng/src/common/defaults.c) file or in the lpd.conf file. I recommend the following: originate_port=512 1022 This is, in fact, now the default in LPRng software. If you get the infamous malformed from address error message from your spooler, then you will have to set originate_port=721 731, and live with a delayed throughput. 22..33.. JJoobb iiss nnoott iinn pprriinntt qquueeuuee,, bbuutt iitt ggeettss pprriinntteedd!! In the original BSD LPD implementation, the LPR program copied users files to a special spool queue directory, and then caused the LPD server to peek in the directory and print the files. This type of operation required spool directory space, special SETUID programs, and a slew of headaches in system security and management. The LPR, LPQ, and other user programs in the LPRng suite use TCP/IP connections and transfer jobs directly to a LPD server running on a remote host, or even the local host if appropriate. Note that this type of operation does not require a LPD server to run on each local machine. In fact, you can have a single host system performing all of your printing. This type of operation is very similar to a central mail server versus individual systems, each having their own mail server and queues. However, some users require or want their jobs to be spooled on the local host system, and then transferred to the remote printer. This is usually the case when some type of processing (filtering) is needed in order to print the job correctly. There are several methods that can be used to force this. Method 1: Explicit Printer Address You can force a job to be sent directly to the pr serviced by the LPD server on host by using the form: lpr -Ppr@host file You can also set the PRINTER environment variable to a similar form, and get the same effect: PRINTER=pr@host; export PRINTER; lpr file Method 2: User and Server Printcap Entries If you want to have the benefits of a printcap file, i.e. - you can use aliases or abbreviations for the names of printers, then here is a couple of hints. First, the LPRng software scans the /etc/printcap file for printcap entries, combining information for the same printer into a single entry. Information found later in the printcap file will override earlier information. In addition, you can tag entries as either being used for all utilities or just for the LPD server. Here are a couple of examples: # for all utilities pr:lp=pr@host # just for LPD pr:server :lp=/dev/lp # more information pr:check_for_nonprintable@ # --- final result for LPR pr:lp=pr@host:check_for_nonprintable@ # --- final result for LPD pr:lp=/dev/lp:check_for_nonprintable@ As you can see, the server keyword indicates that the printcap entry is only for the printer. The LPR utility will send the job to the host, while the LPD server will print it on /dev/lp. Note that the lp=... information overrides the :rp: (remote printer) and :rm: (remote machine) fields if they are present. Method 3: Force sending to server on localhost The force_localhost printcap or configuration flag forces non-LPD applications to send all requests and print jobs to the server running on the local host. This method is similar to the previous one, but has the benefit that it can be configured as a global (i.e. - applies to all printers) rather than printer specific. You can put this in the /etc/lpd.conf file for general application, or have a printcap entry of the following form: # for all utilities pr:lp=pr@host:force_localhost The LPD server will ignore the force_localhost flag, and send jobs to the pr queue on the host machine. However, the LPR, LPQ, etc., utilities will send their requests to the server running on the local host. 22..44.. JJoobb ddiissaappppeeaarrss aanndd iiss nneevveerr pprriinntteedd,, bbuutt llpprr wwoorrkkss This is a rather disconcerting problem, and usually occurs when sending jobs to either a network printer or a nonconforming ``RFC1179'' print spooler. For details about LPRng and RFC1179, see ``RFC1179 and LPRng'', but here is a quick explanation. An LPD job consists of a control file, which contains information about the job, and one or more data files. RFC1179 is silent on the order that jobs are sent; however some implementations REQUIRE that the data files be sent first, followed by the control file. SOLUTION: Set the send_data_first flag in the printcap for the particular printer, or in the lpd.conf configuration file. This is: :send_data_first: (printcap) send_data_first (lpd.conf) Note that some printers/servers INSIST on the control file first; You can clear the flag using send_job_first@ if you need to. 22..55.. II ggeett mmeessssaaggeess aabboouutt bbaadd ccoonnttrrooll ffiillee ffoorrmmaatt RFC1179 describes a set of fields that MAY appear in the control file. It is silent if other ones can appear as well. Unfortunately, some implementations will reject jobs unless they contain ONLY fields from a very small set. In addition, RFC1179 is silent about the ORDER the fields can appear. LPRng quite happily will accept jobs from poor or nonconforming RFC1179 spooler programs, and fix them up to be comformant. See ``Fixing Bad Jobs'' for details. If you are sending jobs to one of a non-conforming spooler, you can force LPRng to send jobs with only the fields described in RFC1179 by setting the the :bk: (BacKwards compatible) flag in the printcap for your printer. 22..66.. WWhhaatt iiss RRFFCC 11117799,, tthhee LLiinnee PPrriinntteerr DDaaeemmoonn PPrroottooccooll?? RFC1179 defines a standard method by which print jobs can be transferred using the TCP/IP protocol between hosts. The standard was developed by simply detailing the way that a version of the BSD LPD software did its job. From the RFC Introduction: RFC 1179 describes a print server protocol widely used on the Internet for communicating between line printer daemons (both clients and servers). RFC1179 is for informational purposes only, and does not specify an Internet standard. Having said this, the RFC then goes on to describe the protocol used by a particular implementation of LPD. The problem was that the RFC did not provide any way to put extensions to the operations into the system, and failed to specify such interesting details as the order in which print jobs and their components could be transferred. Comment by Patrick Powell : Since 1988, there have been a large number of print spooling systems developed which claim RFC1179 conformance, but which are mutually incompatible. Rather than live with the limited capabilities of the RFC1179 standard, LPRng has extended them by adding capabilities to perform remote control of print spoolers, encrypted and authenticated data transfers, and other operations missing from the RFC1179 specification. However, great effort was made to be backwards compatible with older and other LPD based systems. LPRng was developed in order to be able to both accept and provide interactions with these systems. It does so by allowing various options to be used to _t_u_n_e how print jobs would be exchanged. Currently, LPRng can be configured to send and receive print jobs between a vast number of the existing spooling systems. It is flexible enough to act as a gateway between non-compatible systems, and has provisions to transform jobs from one format to another in a dynamic manner. For a detailed explanation about LPRng and RFC1179, see ``RFC1179 and LPRng''. 22..77.. II wwaanntt ttoo rreeppllaaccee llpp,, llppssttaatt,, eettcc,, bbuutt mmyy pprrooggrraammss nneeeedd tthheemm LPRng was designed as a replacement the BSD printing system. As such, it inherited its command names and options from the latter. As you might know, System V uses a totally different set of commands, incompatible with the BSD ones. The good news is that the LPRng binaries include an emulation for the System V commands. (See ``lp Simulation'' for details. Briefly, you create links to the appropriate programs, and invoke them by the link names. _A_c_t_u_a_l_l_y_, _t_h_e_s_e _l_i_n_k_s _a_r_e _i_n_s_t_a_l_l_e_d _b_y _d_e_f_a_u_l_t _i_n _r_e_c_e_n_t _v_e_r_s_i_o_n_s_. ln -s lpr lp ln -s lpq lpstat ln -s lprm cancel If you make these links, calling lp, lpstat and cancel will give you a (partial) SVR4 emulation. They have their own man pages, which you should read if you need the emulation. Since it is a ppaarrttiiaall emulation, you shouldn't expect everything to work. In particular, I would guess that any script which relies on the output format of one of your system binaries will break. Again, see ``lp Simulation'' for more details or additional suggestions. 22..88.. WWhhaatt aarree tthhee ddrraawwbbaacckkss ttoo LLPPRRnngg?? There are many reasons to run LPRng, and most of them are related to the extra features it has, compared to vanilla BSD LPR. A short list is given in section ``What is LPRng?''. (A more elaborate description can be found in the LPRng package itself.) On the other hand, there are also reasons nnoott to switch to LPRng: +o It is a complex system, and you'll probably need a lot of time to get it working. +o Switching from a System V system will require even more work. On the other hand, getting System V printing to work correctly for you may be even more work. +o You don't need any of the enhanced features, and are not worried about security issues. +o While there are many resources and books devoted to the old BSD printer daemon, documentation for LPRng is rather limited: apart from the Introduction documents in the distribution package, there's only this HOWTO (at least, to the best of my knowledge). You should take these elements into account while deciding whether to stick with your old software or not. If you do not decide in favor of LPRng, you can stop reading here. 33.. IInnssttaalllliinngg yyoouurr pprriinntteerr In the following text, I will assume that your printer itself is working properly. I.e., you are able to send data to the printer in such a way that it responds by - well, printing the text :) How to ensure this is highly system-dependent and falls outside the scope of this document. However, here are some hints. 33..11.. PPaarraalllleell PPrriinntteerrss Gordon Haverland supplied this little script, that will put you on the right track: #!/bin/sh #set -v -x # uncomment for debugging PATH=/bin:/usr/bin printer= for $i in $*; do case $i in /dev/*) printer=$i ;; *) ;; esac done if test -z "$printer"; then echo USAGE: $0 device_name ; exit 1; fi; echo PRINTER TEST to $printer 1>&2 for i in 1 2 3 4 5 6 7 8 9; do echo $i > $printer; done echo -e \\r\\f > $printer exit 0; If your printer is connected to the device name you provided, then you should get a page of something out. If the output suffers from the ``staircase'' effect, you will see the numbers ``marching'' across the page, otherwise the numbers will all be in a single column. 33..22.. SSeerriiaall PPrriinntteerrss If your printer is attached by a serial line, then you may need to set the serial line characteristictics before sending the job to the printer. Here are a set of guidelines to following when attaching a serial port printer to a serial line. 1. Check to make sure that the line is not enabled for login. Logins are usually managed by the getty (BSD) or ttymon (Solaris, SystemV). Check your system documentation and make sure that these daemons are not managing the serial line. 2. Check the permissions and ownership of the serial line. For the most easy testing, set the permissions to 0666 (everybody can open for reading and writing). After you have made sure that you can send jobs to the printer, you might want to change the ownership of the serial line to the LPD server and change the permissions to 0600. 3. Make sure that you can print a test file on the printer via the serial port. This may require setting the line characteristictics and then sending a file to the printer. You should try to use 8 bit, no parity, with hardware flow control and no special character interpretation, and definitely no LF to CR/LF translation. The problem is that different versions of UNIX systems have different sets of stty(1) commands to do this. The following simple test script can help in this. #!/bin/sh # 9600, no echo, no CR FLAGS= 9600 -raw -parenb cs8 crtscts DEV= /dev/tty01 (stty $FLAGS; stty 1>&2; cat $1 ) <$DEV >$DEV This shows using stty to set the flags, then to print the current settings, and then using cat a file to the output. If you attach a dumb terminal to the serial port, you can even use this script to ensure that input from the device is echoed to the output with the correct speed, parity, etc. 33..22..11.. CCoonnvveerrttiinngg BBSSDD ffcc,,ffss,,xxcc,,xxss TToo LLPPRRnngg ssttttyy Justin Mason and Updated by Patrick Powell : One of the worst things about old LPDs is that they expected you to give it line characteristictics as octal numbers, using the fc,fs,xc,xs printcap parameters. There are a number of disadvantages to this, compared to using the stty parameter. The stty format is portable, as it is supported on all UNIXes, rather than simply BSD-derived ones; it's also mmuucchh easier to understand than the fc,fs,xc,xs format -- compare the two: # new format :stty=pass8 -parity tabs litout nl: # old format :fc#0000374:fs#0000003:xc#0:xs#0040040: Note, also, that sy uses the same symbolic names as the stty command, which is (relatively) well documented. Anyway, assuming you have a set of printcaps which use the fc,fs,xc,xs method, you can convert them to sy strings using the following table. Each parameter is an octal number, composed by logical-or'ing the bits for the desired parameters together. The bit patterns below have been worked out from SunOS 4.1.2 /usr/include/sys/ttold.h. For example, the following fc,fs,xc,xs set: :fc#0000374:fs#0000003:xc#0:xs#0040040: converts to the following sy string: :stty=-parity -echo -crmod -raw -lcase tandem cbreak litout decctq: Quite often, the resulting strings seem a little complicated, but usually they can be broken down using combination modes. See the printcap(5) manual page for details of which combination modes LPRng supports. In order to help you, the 'xlate' program can be used to translate from the old to the new form. For example: #> xlate ":fc#0000374:fs#0000003:xc#0:xs#0040040:" fc = 374 clear LCASE (simulate lower case) try '-lcase' clear ECHO (echo input) try '-echo' clear CRMOD (map \r to \r\n on output) try '-crmod' clear RAW (no i/o processing) try '-raw' clear ODDP (get/send odd parity) try '-oddp' clear EVENP (get/send even parity) try '-evenp' clear ANYP (get any parity/send none) try '-parity? anyp? pass8? (caution)' fs = 3 set TANDEM (send stopc on out q full) try 'tandem' set CBREAK (half-cooked mode) try 'cbreak' xc = 0 xs = 40040 set LITOUT (literal output) try 'litout' set DECCTQ (only ^Q starts after ^S) try 'decctlq' Note that when you clear odd and even parity, then you get no parity or any parity. You should use -parity to be compatible. You might also want to add 'pass8' as well. Thus, using the xlate output, you would try: :stty=-lcase -echo -crmod -raw -parity pass8 tandem cbreak litout decctlq: Bits used in the fc, fs parameters: TANDEM 00000001 /* send stopc on out q full */ CBREAK 00000002 /* half-cooked mode */ LCASE 00000004 /* simulate lower case */ ECHO 00000010 /* echo input */ CRMOD 00000020 /* map \r to \r\n on output */ RAW 00000040 /* no i/o processing */ ODDP 00000100 /* get/send odd parity */ EVENP 00000200 /* get/send even parity */ ANYP 00000300 /* get any parity/send none */ NLDELAY 00001400 /* \n delay */ NL0 00000000 NL1 00000400 /* tty 37 */ NL2 00001000 /* vt05 */ NL3 00001400 TBDELAY 00006000 /* horizontal tab delay */ TAB0 00000000 TAB1 00002000 /* tty 37 */ TAB2 00004000 XTABS 00006000 /* expand tabs on output */ CRDELAY 00030000 /* \r delay */ CR0 00000000 CR1 00010000 /* tn 300 */ CR2 00020000 /* tty 37 */ CR3 00030000 /* concept 100 */ VTDELAY 00040000 /* vertical tab delay */ FF0 00000000 FF1 00040000 /* tty 37 */ BSDELAY 00100000 /* \b delay */ BS0 00000000 BS1 00100000 ALLDELAY 00177400 Bits used in the xc, xs parameters: CRTBS 00000001 /* do backspacing for crt */ PRTERA 00000002 /* \ ... / erase */ CRTERA 00000004 /* " \b " to wipe out char */ TILDE 00000010 /* hazeltine tilde kludge */ MDMBUF 00000020 /* start/stop output on carrier intr */ LITOUT 00000040 /* literal output */ TOSTOP 00000100 /* SIGSTOP on background output */ FLUSHO 00000200 /* flush output to terminal */ NOHANG 00000400 /* no SIGHUP on carrier drop */ CRTKIL 00002000 /* kill line with " \b " */ PASS8 00004000 /* pass 8 bits */ CTLECH 00010000 /* echo control chars as ^X */ PENDIN 00020000 /* tp->t_rawq needs reread */ DECCTQ 00040000 /* only ^Q starts after ^S */ NOFLSH 00100000 /* no output flush on signal */ The following program translates the various bits to stty flags. #include #include struct bits{ char *name; int bitfields; char *comment; char *try; int mask; }; /* f flags - used with the TIOCGET and the struct sgttyb.sg_flags field */ struct bits tiocget[] = { { "TANDEM",00000001, "send stopc on out q full", "tandem" }, { "CBREAK",00000002, "half-cooked mode", "cbreak" }, { "LCASE",00000004, "simulate lower case", "lcase" }, { "ECHO",00000010, "echo input", "echo" }, { "CRMOD",00000020, "map \\r to \\r\\n on output", "crmod" }, { "RAW",00000040, "no i/o processing", "raw" }, { "ODDP",00000100, "get/send odd parity", "oddp" }, { "EVENP",00000200, "get/send even parity", "evenp" }, { "ANYP",00000300, "get any parity/send none", "parity? anyp? pass8? (caution)" }, { "NL0",0000000, "new line delay", "nl??",00001400 }, { "NL1",00000400, "new line delay tty 37", "nl??",00001400 }, { "NL2",00001000, "new line delay vt05", "nl??",00001400 }, { "NL3",00001400, "new line delay", "nl??",00001400 }, { "TAB0",00000000, "tab expansion delay", "tab??",00006000 }, { "TAB1",00002000, "tab expansion delay tty 37", "tab??",00006000 }, { "TAB2",00004000, "tab expansion delay", "tab??",00006000 }, { "XTABS",00006000, "expand tabs on output", "tabs" }, { "CR0",00000000, "cr??", "",00030000 }, { "CR1",00010000, "tn 300", "cr??",00030000 }, { "CR2",00020000, "tty 37", "cr??",00030000 }, { "CR3",00030000, "concept 100", "cr??",00030000}, { "FF1",00040000, "form feed delay tty 37", "ff??" }, { "BS1",0010000, "backspace timing", "bs??" }, { 0 } }; /* x flags - used with the TIOCLGET and the struct sgttyb.sg_flags field */ struct bits tiolget[] = { { "CRTBS",00000001, "do backspacing for crt", "crterase" }, { "PRTERA",00000002, "\\ ... / erase", "prterase" }, { "CRTERA",00000004, "\"\\b\" to wipe out char", "crterase" }, { "TILDE",00000010, "hazeltine tilde kludge", "don't even think about this" }, { "MDMBUF",00000020, "start/stop output on carrier intr", "crtscts" }, { "LITOUT",00000040, "literal output", "litout" }, { "TOSTOP",00000100, "SIGSTOP on background output", "tostop" }, { "FLUSHO",00000200, "flush output to terminal", "noflsh?? (caution)" }, { "NOHANG",00000400, "no SIGHUP on carrier drop", "nohand" }, { "CRTKIL",00002000, "kill line with \"\\b\"", "crtkill" }, { "PASS8",00004000, "pass 8 bits", "pass8" }, { "CTLECH",00010000, "echo control chars as ^X", "echok" }, { "PENDIN",00020000, "tp->t_rawq needs reread", "don't even think about this" }, { "DECCTQ",00040000, "only ^Q starts after ^S", "decctlq? -ixany? (caution)" }, { "NOFLSH",00100000, "no output flush on signal", "noflsh" }, { 0 } }; char *msg[] = { "xlate optionstrings", " Example", " xlate \":fc#0000374:fs#0000003:xc#0:xs#0040040:\"", 0 }; usage() { char **m; for( m = msg; *m; ++m ){ fprintf( stderr, "%s\n", *m ); } exit( 1 ); } main( argc, argv ) int argc; char *argv[]; { char *s, *end, *value; int c, v, set; struct bits *table; if( argc != 2 ) usage(); for( s = argv[1]; s && *s; s = end ){ end = strchr( s, ':' ); if( end ){ *end++ = 0; } while( (c = *s) && isspace( c ) ) ++s; if( c == 0 ) continue; /* now translate option */ value = strchr( s, '#' ); if( value == 0 ) usage(); *value++ = 0; v = strtol( value, (char **)0, 0 ); printf( "%s = %o\n", s, v); switch( s[0] ){ case 'f': table = tiocget; break; case 'x': table = tiolget; break; default: usage(); } switch( s[1] ){ case 's': set = 1; break; case 'c': set = 0; break; default: usage(); } /* now we scan down the values */ for(; table->name; ++table ){ if( (table->bitfields & v) && ( ((table->bitfields & v) ^ table->bitfields) & (table->mask?table->mask:~0) ) == 0 ){ printf( " %s %s (%s) try '%s%s'\n", set?"set":"clear", table->name, table->comment, set? "":"-", table->try ); } } } } 33..33.. NNeettwwoorrkk PPrriinntteerrss If you have a network printer, then you may have several options. First, your printer may have built-in LPD server support. However, this may not function as expected. It has been observed that most of these builtin servers do not correctly handle large jobs or jobs with complex PJL, PCL, or PostScript with binary information. On the other hand, your printer may have a TCP/IP port that connects directly to the print engine. For example, on the HP JetDirect cards, sending a print file to port 9100 will cause the print engine to process and print it. In addition, this channel may provide status and other information during the printing process. You can use the netcat utility by Hobbit to send files directly to the printer. The simplest and easiest way to print a file to a network printer appears to be: nc printer.ip.addr 9100 < file . 44.. IInnssttaalllliinngg tthhee pprrooggrraammss The basic components of the LPRng system are the executables and the database files. This section deals with generating and installing the executable files. 44..11.. FFiilleess aanndd SSeettuupp The LPRng system can run in several different manners. However, for most users it will require the executables for the server lpd, and the client applications for job submission - lpr, job status - lpq, job removal - lprm, and server management - lprc, and the /etc/lpd.conf and /etc/printcap files. By default, all the LPRng executables are installed in /usr/local/bin, which differs from other UNIX lpr systems, which scatter them in various hidden and arcane locations. Note that the original printing system executables will need to be renamed or removed after installing LPRng. The ``/etc/lpd.conf'' file contains the configuration information for the server and application programs. The LPRng system has a compiled in set of defaults that should be suitable for most user applications. In fact, the default /etc/lpd.conf does not override any of the precompiled values. The ``/etc/printcap'' file contains the printer database information. This information can override the defaults in /etc/lpd.conf 44..22.. SSoouurrccee CCooddee aanndd IInnssttaallllaattiioonn If you have a binary distribution, you can skip this section. However, since LPRng is a rapidly evolving package, I would advise you to check whether there is a newer stable version available on one of the ``FTP sites.'' There should be a link to this stable version called LPRng- stable.tar.gz. You should also look at the ``System specific notes'' to see if there are any special things that you need to do for your system. 44..22..11.. BBuuiillddiinngg tthhee ssooffttwwaarree Before you start to build the software, you should read the README.1st and README.installation files in the distribution. If you have GNU Make, do: ./configure; #if you want internationalization, # ./configure --enable-nls make clean all; su # you must do the following commands as root make install # if you have not installed LPRng before, # install default lpd.perms and lpd.conf file in /etc if [ ! -f /etc/lpd.perms ]; then make default; fi; # update permissions, create files needed for LPRng, check # /etc/printcap file for problems. Do as root: ./src/checkpc -f If you have BSD make do: ./configure; #if you want internationalization, # ./configure --enable-nls make -f Makefile.bsd clean all; su # you must do the following commands as root make -f Makefile.bsd install # if you have not installed LPRng before, # install default lpd.perms and lpd.conf file in /etc if [ ! -f /etc/lpd.perms ]; then make -f Makefile.bsd default; fi; # update permissions, create files needed for LPRng, check # /etc/printcap file for problems. Do as root: ./src/checkpc -f Use the configure --bindir option to specify the location of the binaries, or edit src/Makefile or src/Makefile.bsd after running configure. The lines you have to change are: INSTALL_BIN = ${exec_prefix}/bin # where daemons are installed: lpd #INSTALL_LIB = ${prefix}/lib INSTALL_LIB = ${prefix}/sbin # where maintenance commands are installed: checkpc, setstatus INSTALL_MAINT = ${exec_prefix}/sbin By default, all LPRng executables are placed in /usr/local/bin. 44..22..22.. PPrroobblleemmss wwiitthh ccoommppiillaattiioonn If you have problems compiling the package, you can try these things: 1. Try gcc instead of your vendor's C compiler. This is the standard compiler used for LPRng. Almost without exception, if you have a ANSI C compatible compiler and libraries a POSIX compatible standard set of system support routines, LPRng will compile and run out of the box. The main problems are with missing or modified system support routines, but configure will usually detect this and set flags to use suitable alternatives. 2. The configure and the make should be run on the target host, especially if the target host has a different version of the operating system. This is extremely important for SunOS or Solaris, where there tend to be changes in the system's include files between versions as well as support libraries. 3. configure and the LPRng software tends to make the assumption that newer versions will not have the same problems that older versions have had. If you are not familiar with GNU configure, read the file INSTALL for instructions. Also read the notes for your OS in section ``System-dependent notes'' for specific installation help (if any). 44..33.. PPrreeppaarriinngg ttoo rruunn tthhee ddaaeemmoonn Don't be too impatient. Take your time to completely read through this HOWTO. Things will be a lot easier when you first set up the configuration files, and then start the new lpd. During the course of these steps, you will have to change some files. Be sure to keep a copy of the original file(s)! 44..33..11.. RReemmoovviinngg EExxiissttiinngg FFaacciilliittiieess Here is a summary and some scripts to help you prepare your site for running the server. 1. Kill off the old server. BSD or Linux: ps -aux |grep lpd kill (pid of lpd server) System V: ps -ea |grep lpsched kill (pid of lpsched server) 2. You should remove or rename the existing print system executables. Use the following script and examine the /tmp/candidates file for possible programs. Remove or rename the non-LPRng versions of the programs. # you might want to track down the old lpr, lpq, lprm binaries find /usr -type file -name lp\* \; -print >/tmp/candidates find /sbin -type file -name lp\* \; -print >>/tmp/candidates # example rename mv /usr/libexec/lpd /usr/libexec/lpd.orig # example link ln -s /usr/local/bin/lpd /usr/libexec/lpd 3. Try starting and running lpd before permanently installing it. You should do the next steps as rroooott. /usr/local/bin/lpd; # start up LPD lpq; # test it with LPQ 44..33..22.. SSttaarrttuupp SSccrriippttss Don't forget to modify your system print startup files, i.e. - the /etc/rc file in most BSD based UNIX systems, or those in /etc/init.d or /sbin/init.d on System V and Linux. You will need to have them reference the LPRng lpd and not the original system executable. For systems that use the System V run-level scripts, you will also likely need to install a symbolic link in the default system run-level directory (perhaps /etc/rc3.d or /sbin/rc3.d) pointing to the master copy of the startup script in the init.d directory. Here is the core of a typical UNIX SystemV or LINUX startup file that can be used to start up and shut down the server. Note that you will most likely need to modify the echo lines. #!/bin/sh case "$1" in start) # Start daemons. echo "Starting lpd: \c"; /usr/local/bin/lpd; bin/echo; ;; stop) # Stop daemons. echo "Shutting down lpd: \c" server=`/usr/local/bin/lpc -Pany@localhost lpd \ | awk '{for(i=1;i<=NF;++i){v=$i+0;if(v>1){ print v;exit;}}}'` if [ -n "$server" ]; then echo " server pid $server"; kill $server; else echo " no server active"; fi; ;; *) echo "Usage: lpd {start|stop}" exit 1 ;; esac 44..44.. RReeppllaacciinngg UUNNIIXX SSyysstteemmVV llpp,, llppssttaatt PPrriinnttiinngg SSeerrvviicceess Many UNIX utilities in the Solaris and HP UNIX environment use the UNIX System V lp and lpstat programs. It is almost impossible to modify their operation to use the LPRng lpr or lpq programs, as they depend on various return codes and information. Here are Patrick Powell's comments on this: After fighting with LP simulation, I finally decided to make the interface part of the LPR/LPQ package. If LPR is invoked as LP, then it will 'act' like a 'semi-compatible' LP; similarly for LPQ and LPSTAT, and LPRM and CANCEL. To get this functionality, you need to either make a symbolic link or a hard link to the appropriate executable. cd /usr/local/bin ln -s lpr lp ln -s lpq lpstat ln -s lprm cancel cd /usr/sbin ln -s /usr/local/bin/lpr lp ln -s /usr/local/bin/lpq lpstat ln -s /usr/local/bin/lprm cancel See the man pages for lp, lpstat, and cancel in the LPRng/man directory. Note that not all the functions of the original lp programs are supported. These man pages should be installed to replace the normal lp, etc, man pages. For some purposes, the rather rugged lpstat simulation provided by this method does not work. Garrett D'Amore has written some much improved versions; take a look at http://people.qualcomm.com/garrett/ for details. 44..55.. SSeettuuiidd RROOOOTT aanndd SSeeccuurriittyy IIssssuueess By default, LPRng executables are installed setuid ROOT. When running, they normally perform all operations with the user's effective UID, and perform all other operations set to the user and group specified by the user=daemon and group=daemon printcap entries, except for a very few places where they take extreme precautions against actions that could cause security breaches, change the EUID to ROOT, and then immediately change back to the normal operation. As a scan of the various CERT Security Advisories will indicate, many programs that run SUID root can be serious security loopholes. While LPRng has been designed and implemented with security and paranoia in mind, there is still the possibility that user level or LPD processes can have an exposed security loophole. To reduce the risk, the user level utilities such as lpr, lprm, lpq, and lpc can be installed non-setuid. This effectively closes several possible security loopholes. To install the executables as non- setuid, the distribution src/Makefile must have the following lines commented out, and then LPRng must be reinstalled: edit src/Makefile # comment out the next line to have LPRng installed non-setuid PERMS=$(SUID_ROOT_PERMS) make install 44..66.. SSyysstteemm ssppeecciiffiicc nnootteess The following are a set of suggestions and recommendations for specific systems. 44..77.. SSoollaarriiss 22..44,, 22..55,, 22..66 The Sun Solaris operating system is derived from the System V UNIX baseline. Use the following installation procedure. 1. First, install the LPRng software and then rename all of the existing Solaris print facilities. See the ``Installation'' section for details. You should especially look out for lp, lpstat, lpsched, lpadmin, and other executables used by Solaris for print support. 2. Next, make sure you update the /etc/rc startup files. During the startup or initialization, Solaris will invoke a set of individual startup files. You will find that the startupfile files are usually links to a common one in the /etc/init.d directory. ># grep -l lpsched /etc/rc* /etc/rc*/* init.d/* init.d/*/* /etc/rc0.d/K20lp /etc/rc2.d/K20lp /etc/rc2.d/S80lp /etc/init.d/lp ># ls -l /etc/rc0.d/K20lp lrwxrwxr-x 1 root bin 1 Dec 29 23:39 /etc/rc0.d/K20lp -> ../../init.d/lp 3. Replace the existing lp startup file with one similar to the ``startup script'' in the previous section. 4. Check the /etc/inetd.conf file for a line like: printer stream tcp nowait root /usr/lib/print/in.lpd in.lpd and remove it if it is present. 5. _R_e_b_o_o_t. Don't try to be fancy and kill off processes, use the _n_l_s_a_d_m_i_n command, or other insanity. This is brutal, but appears to be necessary in order to ensure that the networking support is set up correctly. 6. When the system restarts, try using lpq to check to see if the lpd server is active. James P. Dugal has also makde the following suggestions as well. From: "Dugal James P." To: lprng@iona.com Subject: Re: [LPRng] start up trouble Here are some more tips for Solaris: 1. If /var/spool/cron/crontabs/lp exists, remove it. In fact, we actually test if /etc/init.d/lp exists on any newly-installed system, and if so, we issue these commands: /etc/init.d/lp stop /usr/sbin/pkgrm -n SUNWpsu /usr/sbin/pkgrm -n SUNWscplp /usr/sbin/pkgrm -n SUNWpcu /usr/sbin/pkgrm -n SUNWpsr /usr/sbin/pkgrm -n SUNWpcr /bin/rm -f /var/spool/cron/crontabs/lp Regards, -- James Dugal, N5KNX Internet: jpd@usl.edu Associate Director Ham packet: n5knx@k5arh.#lft.la.usa.noam Computing Support Services US Mail: PO Box 42770 Lafayette, LA 70504 University of Southwestern LA. Tel. 318-482-6417 U.S.A. 44..88.. SSoollaarriiss,, NNeewwsspprriinntt aanndd FFrraammeeMMaakkeerr The following is a guide to using LPRng and Sun Microsystems Newsprint by Christopher Hylands, Ptolemy Project Manager of the University of California. The Sun Newsprint printer is actually an OEM version of the Textronix PhaserII; Sun Microsystems appears to have dropped support for Newsprint, and the recommended migration path is to buy a PostScript printer. If you want more information on using the Newsprint system, notes are available via http://ptolemy.eecs.berkeley.edu/~cxh/lprng.html. Looking through the mailing list logs, it looks like everyone was having a hard time getting lprng to work with Sun's braindead newsprinters. I tried using ghostscript, but the fonts were, IMHO, ugly, so I spent a little time getting the newsprint fonts to work. The key thing was to grab the file /usr/newsprint/lpd/if from a SunOS4.1.3 newsprint installation. If you cannot get this code, then the installation will be extremely difficult. To install lprng on a Solaris2.x machine, you need to first stop the existing print services and install the startup scripts for LPRng. Note that if there is a local printer, you may have to also fix the permissions of the device. Typical commands are: chown daemon /devices/sbus@1,f8000000/SUNW,lpvi@1,300000:lpvi0 We use the following simple if script. #/bin/sh # extremely simple filter script /bin/cat The Sparcprinters use licensed fonts from NeWSprint. To use the licensed fonts, you must have the lprng spool directory for the sparcprinter in the same location as spool directory of the brain dead Solaris lp system. If your printer is named xsp524, then this directory would be /etc/lp/printers/xsp524. The printcap entry looks like: sp524|524: :mx#0:sf:sh:sb: :lp=:rm=doppler:rp=xsp524:mx#0: :sd=/var/spool/lpd/sp524d: :lf=/var/spool/lpd/sp524d/log: xsp524|Sun SPARCprinter NeWSprint printer: :mx#0:sf:sb:sh:rs: :lp=/dev/lpvi0: :sd=/etc/lp/printers/xsp524: :lf=/etc/lp/printers/xsp524/log: :af=/var/spool/lpd/xsp524/acct: :if=/usr/local/lib/newsprint/if: The /usr/local/lib/newsprint/if was copied from /usr/newsprint/lpd/if in a SunOS4.x installation of the newsprint software. Unfortunately, the newsprint engine is so brain dead that it needs many environment variables set, so it is fairly difficult to come up with a clean script to start the engine. I made the following changes to the file. 1. First, set the path in the script. You may also need to change defaults to suit your preferences: PATH=/usr/ucb:/usr/bin:/etc:/usr/etc:/opt/NeWSprint/bin:/opt/NeWSprint/np/bin: PATH=$PATH:$NPHOME/pl.$ARCH/bin:$NPHOME/np/bin; export PATH 2. You will also need a /etc/lp/printers/printername/.params file. If you are using the same spooler directory as the directory that the Solaris lp system uses, then the .param file should appear there. If you are using a different spooler directory, then you will need to copy the .param file from elsewhere and edit it accordingly. 3. If you are going to move a license to a new printer, you should probably save the .param file in the old printer spooler directory. Run /opt/NeWSprint/bin/fp_install and remove the license from the old printer and assign it to the new printer. You could run /opt/NeWSprint/bin/rm_np_printer and remove the printer, but that will get rid of the .param file 4. FrameMaker under Solaris2.x uses the lp command. The fix is to edit $FMHOME/fminit/FMlpr and comment out the lp line and add an lpr line sunxm.s5.sparc) lpr -P"$PRINTER" "$FILE" #lp -c -d"$PRINTER" "$FILE" Christopher Hylands, Ptolemy Project Manager University of California cxh@eecs.berkeley.edu US Mail: 558 Cory Hall #1770 ph: (510)643-9841 fax:(510)642-2739 Berkeley, CA 94720-1770 home: (510)526-4010 (if busy -4068) (Office: 493 Cory) 44..99.. LLiinnuuxx At the time of this writing (Jan 1998), the three major Linux distributions (Slackware, Red Hat and Debian) carry an older version of LPRng. Users of those systems should download the latest stable release, and install that instead of the distributed binaries. This is mostly important for Slackware 3.2 users, as this version installs LPRng by default. Patrick Volkerding changed the default back to BSD LPR in Slackware 3.3, as many users had experienced problems because they didn't realize they weren't using the BSD software. Debian's dselect utility lets you choose between all packages. Amongst these are LPRng, as well as the traditional LPR software. You have to make sure your kernel is configured correctly. The documentation for the kernel sources in /usr/src/linux/Documentation/ and the Kernel-HOWTO will help you to generate a new kernel if needed. You will need to set the following options: +o Networking support (CONFIG_NET) +o TCP/IP support (CONFIG_INET) +o If your printer is connected to a parallel port, you will also need the `Parallel Printer Support' (CONFIG_PRINTER). You can use this as a module if you want. +o For a serial printer, answer `Yes' when asked if you want `Support for serial devices' (CONFIG_SERIAL). This is also available as a module. Once you have done this, the current releases of LPRng will install and run without problems. See the ``Installing the programs'' section for details on how to install LPRng and deactivate the existing print support. You may need to update the printcap file and filters. See ``/etc/printcap Print Spool Database File'' for details. 44..1100.. AAIIXX This information was supplied by Dirk Nitschke, as of August 1997, and describes how to install the LPRng package on a workstation running AIX 4.1.x and possibly 3.x.x as well. Dirk would be interested in any comments or corrections. Printing on AIX systems is different. AIX provides a general queueing facility and printing is only one way to use it. You submit a print job to a print queue using one of the commands qprt, enq. You can use the BSD or System V printing commands lpr or lp, too. The qdaemon watches all (general) queues and knows how to handle your job. A (general) queue is defined in the file /etc/qconfig. The format of this file is different from the printcap format. OK, how to replace the AIX printing system? There is no group daemon on AIX. Therefore you have to change the default group for file ownership and process permissions. We decided to use the printq group. The user daemon exists on AIX but we have chosen lpd as the user who runs lpd and all filters and owns the spooling directories. You can change the values for group, server_user and user in your lpd.conf file or in the sources src/common/default.c. This is an example for lpd.conf: # lpd.conf for AIX (change group, server_user and user) group=printq server_user=lpd user=lpd Compile and install the LPRng package. Create your printcap, spooling directories, accounting and logfiles and so on. Don't forget to use ``checkpc'' to make sure that all the permissions are set correctly and the necessary files are created. Then stop all print queues defined on your workstation. Use # chque -q queuename -a "up = FALSE" for this (yes, blanks around = are needed). If you have local printers attached to your system you will have an lpd running. Stop this daemon using SMIT (Print Spooling, Manage Print Server, Stop the Print Server Subsystem). Choosing both also removes lpd from /etc/inittab. Maybe it's faster to do this by hand: # stopsrc -p'pid of /usr/sbin/lpd' # rmitab "lpd" Now delete all print queues (managed by qdaemon) defined on your system. You can use SMIT for this or the commands {mk,ch,rm}que, {mk,ch,rm}quedev, {mk,ch,rm}virprt. The SMIT fast path is smit rmpq. To start the new lpd at system startup you have to add an entry to /etc/inittab: # mkitab "lpd:2:once:/full/path/lpd" Some work has to be done if have have a local printer attached to your workstation. You have to create a device file like /dev/lp0. The SMIT fast path for this is smit mkdev. Choose Printer/Plotter and then Printer/Plotter Devices. Now Add a Printer/Plotter. To create a parallel printer device select the following: Plotter type: opp Other parallel printer Printer/Plotter Interface: parallel Parent Adapter: ppa0 Available Now define the characteristictics of the device: Port Number: p (p is for parallel). Go to the field Send all characters to printer UNMODIFIED no and select yes! We have had a lot of trouble with no. This is very important! Expect erroneous output if you choose no. If you have already created a device file, change the characteristictics! SMIT's fast path is smit chdev. Finally remove all AIX printing commands like qprt, lp, cancel, lpr, lprm. You will find a lot of them in /usr/bin. Do not remove enq and friends if you want to use the general queueing facility. Now you can start your new lpd. 44..1111.. AApppplleettaallkk SSuuppppoorrtt Netatalk is used to communicate from TCP/IP to Appletalk printers and vice versa. The netalk distribution FAQ is at: http://www.umich.edu/~rsug/netatalk There are two issues with using netatalk. The first issue has to do with printing to LPRng-served printers from Macs. The second issue has to do with printing from LPRng to network printers that speak AppleTalk. 44..1122.. AAppppllee ttoo LLPPRRnngg PPrriinnttiinngg After you have installed and gotten netatalk working, you can use the following configuration file to print from a Macintosh to an LPRng printer. From edan@mtu.edu Mon Sep 29 21:31:25 1997 Date: Tue, 30 Sep 1997 00:04:58 -0400 (EDT) From: Edan Idzerda To: lprng@iona.com Subject: Re: [LPRng] Netatalk configuration file > Somebody posted a very nice Netatalk papd.conf file > that showed the setup for LPRng. If anybody has this > handy could you post it? Well, *I* use: Your 32 Character Printer Name:\ :pr=|/your/path/to/lpr -Pprintername :ppd=/your/path/to/ppd/files/yourprinter.ppd -- Edan Idzerda System Administrator -- Michigan Technological University, Houghton MI USA 44..1133.. LLPPRRnngg ttoo AApppplleettaallkk PPrriinnttiinngg The netatalk package comes with a PostScript filter called psf. After compilation, it is in (e.g.) netatalk-1.4b2/etc/psf and will be installed in (e.g.) /usr/local/atalk/etc/. After installation, there will also be a directory /usr/local/atalk/etc/filters that contains ifpap, ofpap, et al. These are just symlinks to psf, and psf will do the appropriate thing based on how it was invoked. If there's a 'pap' in the name, psf uses AppleTalk to talk to the printer. See psf(8) for more information. A printcap entry for a network printer looks like the following: dave|Dave's 32 Character Printer Name:\ :sd=/var/spool/dave:\ :lf=/var/adm/lpd-errs:\ :lo=lock:\ :if=/usr/local/atalk/etc/filters/ifpap:\ :of=/usr/local/atalk/etc/filters/ofpap:\ :lp=/var/spool/dave/null There are three caveats to using netatalk this way. 1. The first is that psf (i.e., the filters) needs to run as root. You can accomplish this in one of two ways. The first is to uncomment the following line in src/Makefile and recompile: # ROOT_CFLAG=-DROOT_PERMS_TO_FILTER_SECURITY_LOOPHOLE The filter lines then need to look like the following: :if=ROOT /usr/local/atalk/etc/filters/ifpap:\ :of=ROOT /usr/local/atalk/etc/filters/ofpap:\ The alternative is to make psf setuid root. To minimize the risk, you may want to make psf executable only by group daemon. (I haven't tested the first option. I'm currently using the second option.) 2. The second caveat is that each network printer needs a .paprc in its spool directory. For instance, /var/spool/dave/.paprc looks like this: Dave's 32 Character Printer Name:LaserWriter@Your AppleTalk Zone See psf(8) and pap(1) for more information. 3. The third caveat concerns the lp line in the printcap entry. For a single printer, this can be /dev/null. If the host spools to more than one AppleTalk printer, you shouldn't use /dev/null for lp. You should use mknod to create a null device for each printer. See psf(8). Chad Mynhier Lab Engineer, CS Department University of Tennessee, Knoxville 44..1144.. SSAAMMBBAA SSuuppppoorrtt From the http://www.samba.org Web Site. 44..1144..11.. WWhhaatt iiss SSMMBB This is a big question. The very short answer is that it is the protocol by which a lot of PC- related machines share files and printers and other information such as lists of available files and printers. Operating systems that support this natively include Windows NT, OS/2, and Linux and add on packages that achieve the same thing are available for DOS, Windows, VMS, Unix of all kinds, MVS, and more. There is no reason why Apple Macs and indeed any Web browser should not be able to speak this protocol, and current development (in which the Samba team is heavily involved) is aimed at exactly that. Alternatives to SMB include Netware, NFS, Appletalk, Banyan Vines, Decnet etc; many of these have advantages but none are both public specifications and widely implemented in desktop machines by default. The Common Internet Filesystem is what the new SMB initiative is called. For details watch http://www.samba.org. WWHHAATT CCAANN SSAAMMBBAA DDOO?? Here is a very short list of what samba includes, and what it does. +o a SMB server, to provide Windows NT and LAN Manager-style file and print services to SMB clients such as Windows 95, Warp Server, smbfs and others. +o a Netbios (rfc1001/1002) nameserver, which among other things gives browsing support. Samba can be the master browser on your LAN if you wish. +o a ftp-like SMB client so you can access PC resources (disks and printers) from unix, Netware and other operating systems +o a tar extension to the client for backing up PCs For a much better overview have a look at the web site at http://www.samba.org and browse the user survey. Related packages include: +o smbfs, a Linux-only filesystem allowing you to mount remote SMB filesystems from PCs on your Linux box. This is included as standard with Linux 2.0 and later. +o tcpdump-smb, a extension to tcpdump to allow you to investigate SMB networking problems over netbeui and tcp/ip. +o smblib, a library of smb functions which are designed to make it easy to smb-ise any particular application. FFTTPP SSIITTEE aanndd WWEEBB SSIITTEE The main anonymous ftp and web site for this software is found using http://www.samba.org. As well as general information and documentation, this also has searchable archives of the mailing list and a user survey that shows who else is using this package. Have you registered with the survey yet? :-) 44..1144..22.. SSaammbbaa aanndd LLPPRRnngg The SAMBA code is very easy to configure. See the SAMBA documentation for details, but you only need to modify the samba.conf file and put in the pathnames of the LPRng facilities. The following is a sample. From: Sascha Ottolski Subject: Re: [LPRng] lprng-3.2.6 and smb on Linux webnut@conc.tds.net said: I have samba sending print from Win95 machines to LPRng. The key to making it work is in the samba.conf file in the [global] section: [global] printing = lprng print command = /usr/local/bin/lpr -P%p %s -r lpq command = /usr/local/bin/lpq -P%p lprm command = /usr/local/bin/lprm -P%p %j printcap name = /etc/printcap load printers = no [printers] comment = All Printers path = /tmp browseable = no printable = yes guest ok = no writable = no create mode = 0700 Note: the path= value specifies the spool directory where the print files are temporarily stored. This should NOT be the LPRng spool directory, but some other directory that Samba has write permissions for. From: "Pascal A. Dupuis" Subject: Re: LPRng-3.2.10 and SAMBA I include the smbprint script used to send stdin to a NetBEUI printer. #!/bin/sh -x # This script is an input filter for printcap printing on a unix machine. It # uses the smbclient program to print the file to the specified smb-based # server and service. # For example you could have a printcap entry like this # # smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint # # which would create a unix printer called "smb" that will print via this # script. You will need to create the spool directory /usr/spool/smb with # appropriate permissions and ownerships for your system. # # The /usr/spool/smb/.config file should contain: # server=PC_SERVER # service=PR_SHARENAME # password="password" # # Set these to the server and service you wish to print to # In this example I have a WfWg PC called "lapland" that has a printer # exported called "printer" with no password. # # E.g. # server=PAULS_PC # service=CJET_371 # password="" # Should read the following variables set in the config file: # server, service, password config_file=.config eval `cat $config_file` # echo "server $server, service $service" 2>&1 ( # NOTE You may wish to add the line `echo translate' if you want automatic # CR/LF translation when printing. # echo translate echo "print -" cat ) | /usr/local/bin/smbclient "\\\\$server\\$service" \ $password -U $server -N -P # comment preceeding line and uncomment following # to just test for correct filter working #) | cat > /dev/null 44..1155.. PPrriinntteerr SSppeecciiffiicc nnootteess This is a small collection of miscellaneous notes about printers and applications. 44..1166.. HHPP DDeesskkjjeett From: jarausch@igpm.rwth-aachen.de (Helmut Jarausch) Subject: Re: Using gs (ghostscript) as a filter? To: lprng@iona.com Cc: Rick Gaine Sender: majordomo-owner@iona.com Reply-To: lprng@iona.com >> >> Hello All: >> >> I would like to use LPRng 3.1.4 with an HP LaserJet 4P. I'd like to be >> able to use gs to convert PostScript files so that I can print them on my >> HP 4P. Can I do this with LPRng? If so, could someone semd me a printcap >> entry? I'd appreciate it. I am not sure how I will be cconnecting the >> printer yet, but I am thinking either serial or network. Probably serial >> though. Thanks for any help. This printcap works for my Deskjet: djps :cm=Local Deskjet(GhostScript) :sd=/var/spool/djps:sf:sh:mx#0 :lp=/dev/plp :if=/usr/LOCAL/bin/LPRng/ps_to_deskjet: and this is the script /usr/LOCAL/bin/LPRng/ps_to_deskjet #!/bin/sh nice -19 /usr/LOCAL/bin/gs -sDEVICE=cdj550 -sPAPERSIZE=a4 -sOutputFile=- -q -r300 - Helmut Jarausch Lehrstuhl f. Numerische Mathematik Institute of Technology RWTH Aachen D 52056 Aachen, Germany 44..1177.. HHPP LLaasseerrJJeett IIIIIISSiiMMXX > From majordomo-owner@iona.com Mon Aug 31 11:17:26 1998 > To: lprng@iona.ie > Subject: [LPRng] problems printing PS-level2 jobs on LJIIIsi's... > Date: Mon, 31 Aug 1998 15:06:22 -0400 > From: "John Saroglou" > > Greetings... > > I'm wondering if someone got around the problem of printing > Postscript(R) Level 2 jobs on Laser Jet IIIsi printers. > Our printers are direct network printers talking to a > print server running solaris 2.6 and lprng-3.5.1. > > Is there a fix (possible drivers?) for such problem? > > Thanks in advance. The LaserJet IIISi does not support PostScript level 2, only level 1 (really, it is called 3SiMX). The Windows (you are under Windows, right?) HP driver for 3Si/3Si MX PostScript should produce only PS level 1. Beware: latest version of Adobe Windows PS driver produces *ONLY* PS level 2. So, if you have (or receive) level 2 files, read them using ghostscript and print a screen dump :-) or as a bitmap. You can too convert them into PDF (using either Adobe distiller or ghostscript ps2pdf) then use acroread to print the result. acroread can produce either level 1 or level 2 PostScript. THE definite solution ! This trouble has nothing to do with the way they are connected or driven, it is only a driver problem. I believe that HP had once a PS level2 update, but the price was so high that bying a new printer was a better solution! Bertrand -- | Bertrand DECOUTY | mailto:Bertrand.Decouty@irisa.fr | | IRISA - INRIA (Atelier) | PHONE : 0299847346 / 0299847100 | | Campus de Beaulieu | FAX : +33 (0) 299842534 | | F-35042 Rennes Cedex - FRANCE | http://www.irisa.fr/ | Olaf_Lotzkat@inf.tu-dresden.de<, and has been update for the ifhp filter. # HP DeskJet 1600CM tinte|: :lp=dj1600cm%9100: :mx#0:rw:sf: :ps=status:af=acct:lf=log:sd=/lpspool/tinte:fx=flpv: :if=/usr/local/lib/filters/ifhp ???? :of=/usr/local/lib/filters/ofhp \ -Tpagecount=off,forcepagecount=on,infostatus=off,sync=off,banner=off: :vf=/usr/local/lib/filters/ifhp -c: :bp=/usr/local/lib/filters/psbanner: > 44..1199.. HHPP JJeettDDiirreecctt IInntteerrffaaccee The HPJetDirect card can be configured through the front panel or through a set of network files. Here is a summary of the methods used from UNIX systems, or when you are desperate, to configure the printer. 44..1199..11.. SSeettttiinngg UUpp IIPP NNeettwwoorrkkiinngg aanndd AAddddrreessss You can set the network address from the front panel. Reset the printer, put it in offline mode. and then use the MENU, +-, SELECT keys as follows: MENU -> MIO MENU (use MENU to display MIO MENU) ITEM -> CFG NETWORK=NO* + -> CFG NETWORK=YES ENTER -> CFG NETWORK=YES* ITEM -> TCP/IP=OFF* (use ITEM to display TCP/IP) + -> TCP/IP=ON ENTER -> TCP/IP=ON* ITEM -> CFG TCP/IP=NO* (use ITEM to display TCP/IP) + -> CFG TCP/IP=YES ENTER -> CFG TCP/IP=YES* ITEM -> BOOTP=NO* (Enable BOOTP if you want to - see below) ITEM -> IP BYTE 1=0* This is IP address MSB byte. Use +- keys to change value, and then ENTER to change Use ITEM keys to get IP BYTE=2,3,4 ITEM -> SM BYTE 1=255* This is the subnet mask value Use +- keys to change value, and then ENTER to change Use ITEM keys to get IP BYTE=2,3,4 ITEM -> LG BYTE 1=255* This is the Syslog server (LoGger) IP address Use +- keys to change value, and then ENTER to change Use ITEM keys to get IP BYTE=2,3,4 ITEM -> GW BYTE 1=255* This is the subnet gateway (router) IP address Use +- keys to change value, and then ENTER to change Use ITEM keys to get IP BYTE=2,3,4 ITEM -> TIMEOUT=90 This is the connection timeout value. It puts a limit on time between connections. A value of 10 is reasonable. 44..1199..22.. BBOOOOTTPP IInnffoorrmmaattiioonn If you have a bootp server, you can put this information in the bootptab file. To use this, you must enable the bootp option on the printer. The T144 option specifies a file to be read from the bootp server. This file is read by using the TFTP protocol, and you must have a TFTPD server enabled. Here is a sample bootptab entry. # Example /etc/bootptab: database for bootp server (/etc/bootpd). # Blank lines and lines beginning with '#' are ignored. # # Legend: # # first field -- hostname # (may be full domain name) # # hd -- home directory # bf -- bootfile # cs -- cookie servers # ds -- domain name servers # gw -- gateways # ha -- hardware address # ht -- hardware type # im -- impress servers # ip -- host IP address # lg -- log servers # lp -- LPR servers # ns -- IEN-116 name servers # rl -- resource location protocol servers # sm -- subnet mask # tc -- template host (points to similar host entry) # to -- time offset (seconds) # ts -- time servers # # Be careful about including backslashes where they're needed. Weird (bad) # things can happen when a backslash is omitted where one is intended. # peripheral1: :hn:ht=ether:vm=rfc1048: :ha=08000903212F: :ip=190.40.101.22: :sm=255.255.255.0: :gw=190.40.101.1: :lg=190.40.101.3: :T144="hpnp/peripheral1.cfg": If you are using the T144 option, you will need to create the configuration file. The sample configuration file from the HP Direct distribution is included below. # # Example HP Network Peripheral Interface configuration file # # Comments begin with '#' and end at the end of the line. # Blank lines are ignored. Entries cannot span lines. # Name is the peripheral (or node) name. It is displayed on the peripheral's # self-test page or configuration plot, and when sysName is obtained through # SNMP. This name can be provided in the BOOTP response or can be specified # in the NPI configuration file to prevent the BOOTP response from overflowing # the packet. The domain portion of the name is not necessary because the # peripheral does not perform Domain Name System (DNS) searches. Name is # limited to 64 characters. name: picasso # Location describes the physical location of the peripheral. This is the # value used by the interface for the MIB-II sysLocation object. The default # location is undefined. Only printable ASCII characters are allowed. # Maximum length is 64 characters. location: 1st floor, south wall # Contact is the name of the person who administers or services the peripheral # and may include how to contact this person. It is limited to 64 characters. # This is the value used by the interface for the MIB-II sysContact object. # The default contact is undefined. Only printable ASCII characters are # allowed. Maximum length is 64 characters. contact: Phil, ext 1234 # The host access list contains the list of hosts or networks of hosts # that are allowed to connect to the peripheral. The format is # "allow: netnum [mask]", where netnum is a network number or a host IP # address. Mask is an address mask of bits to apply to the network number # and connecting host's IP address to verify access to the peripheral. # The mask usually matches the network or subnet mask, but this is not # required. If netnum is a host IP address, the mask 255.255.255.255 can # be omitted. Up to ten access list entries are permitted. # to allow all of network 10 to access the peripheral: allow: 10.0.0.0 255.0.0.0 # to allow a single host without specifying the mask: allow: 15.1.2.3 # Idle timeout is the time (in seconds) after which an idle # print data connection is closed. A value of zero disables # the timeout mechanism. The default timeout is 90 seconds. idle-timeout: 120 # A community name is a password that allows SNMP access to MIB values on # the network peripheral. Community names are not highly secure; they are # not encrypted across the network. The get community name determines which # SNMP GetRequests are responded to. By default, the network peripheral # responds to all GetRequests. The get community name is limited to 32 # characters. # # For hpnpstat and hpnpadmin, the community name can be stored in # /usr/lib/hpnp/hpnpsnmp. get-community-name: blue # The set community name is similar to the get community name. The set # community name determines which SNMP SetRequests are responded to. In # addition, SetRequests are only honored if the sending host is on the # host access list. By default, the network peripheral does not respond # to any SetRequests. The set community name is limited to 32 characters. # # The set community name can come from /usr/lib/hpnp/hpnpsnmp # if it is the same as the get community name. We recommend that the # set community name be different from the get community name though. set-community-name: yellow # SNMP traps are asynchronous notifications of some event that has occurred. # SNMP traps are useful only with network management software. Traps are # sent to specific hosts and include a trap community name. Up to four # hosts can be sent SNMP traps. The trap community name is limited to # 32 characters. The default name is public. trap-community-name: red # The SNMP trap destination list specifies systems to which SNMP # traps are sent. Up to four IP addresses are allowed. If no # trap destinations are listed, traps are not sent. trap-dest: 15.1.2.3 trap-dest: 15.2.3.4 # The SNMP authentication trap parameter enables or disables the sending # of SNMP authentication traps. Authentication traps indicate that an SNMP # request was received and the community name check failed. By default, # the parameter is off. authentication-trap: on # The syslog-facility parameter sets the source facility identifier that the # card uses when issuing syslog messages. Other facilities, for example, # include the kernel (LOG_KERN), the mail system (LOG_MAIL), and the spooling # system (LOG_LPR). The card only allows its syslog facility to be configured # to one of the local user values (LOG_LOCAL0 through LOG_LOCAL7). The # selectable option strings, local0 through local7 (configured to LOG_LOCAL0 # through LOG_LOCAL7, respectively) are case insensitive. The default # syslog-facility for the card is LOG_LPR. syslog-facility: local2 # This parameter allows the card to treat hosts on other subnets as if the # hosts were on the card's subnet. This parameter determines the TCP # Maximum Segment Size (MSS) advertised by the card to hosts on other subnets # and affects the card's initial receive-window size. The card will use a # TCP MSS of 1460 bytes for local hosts, and 536 bytes for a non-local host. # The default is off, that is, the card will use the maximum packet sizes # only on the card's configured subnet. # # The configuration utility does not allow access to this parameter. If you # want to configure it, you must manually edit the NPI configuration file # and add it to the bottom of the entry for the network peripheral. subnets-local: on # This parameter affects how the card handles TCP connection requests from # the host. By default, the JetDirect MPS card will accept a TCP connection # even if the peripheral is off-line. If this parameter is set to "on", then # the card will only accept a TCP connection when the peripheral is on-line. old-idle-mode: off 44..1199..33.. PPaappeerr TTrraayy SSeelleeccttiioonn Be careful with your paper tray selection. You should configure the printer, using the front panel switches, to select the FIRST paper tray. See your printer documentation on this. Unfortunately, different models of HP printers have different methods of handling paper trays. 44..2200.. LLeexxmmaarrkk PPrriinntteerrss Some Lexmark printers do not send _e_n_d _o_f _j_o_b status back unless configured to do so. Here is what is needed to force this. Date: Wed, 21 Jan 1998 18:25:50 -0600 (CST) From: Matt White To: lprng@iona.com Subject: Re: [LPRng] ifhp with Lexmark Optra N printer On Wed, 21 Jan 1998, Simon Greaves wrote: > Apologies in advance if this is way off mark, but we've been evaluating a > commercial print charging package (Geomica) which works by talking to the > printer in what I think is a similar way to the ifhp filters. Lexmarks are > currently a big headache because they seem to fail to return the message > that they have finished printing which screws things up somewhat. In our > case, it is believed to be a problem with the Lexmark firmware which they > are looking into. There is a fix for that...it is originally from the Lexmark 4039 series, but it still works on the Optra S 1650 machines that we have (and should work on the rest of the optra line). Just send this little chunk of postscript to the printer once: -----------snip---------- %! Postscript utility file to set the 4039 printer into synchronous mode serverdict begin 0 exitserver statusdict begin true setenginesync end -----------snip---------- Basically, it causes the printer to wait until it is finished printing before actually reporting that it is done. I've got 3 Optra S printers running with ifhp right now with no extra options (just defaults). --------------------------------------------------------------------- - Matt White whitem@arts.usask.ca - - Network Technical Support http://arts.usask.ca/~whitem - - College of Arts & Science University of Saskatchewan - --------------------------------------------------------------------- 44..2211.. TTeekkttrroonniixx PP445500 aanndd FFaammiillyy The Tektronix P450 has a very odd network interface. You can open a TCP (stream) connection to port 9100 and send a file to be printed on the connection. When a UDP datagram is sent to UDP Port 9101, the printer resonds with status information. This apparently is the poor man's SNMP, but I digress. Here is a clever implementation of a filter that handles this printer. From: Russ Thacher To: lprng@iona.com Subject: Re: [LPRng] Tektronix P450 & psfilter Having only limited success with the psfilter UDP status port option, and not satisfied with the overall slowness of sending print jobs out via AppleShare with CAP, I (we) decided to roll our own filter for the Phaser 450 that speaks AppSocket (sending on TCP 9100, monitoring UDP 9101), grabs reliable page counts and can tell the Phaser to switch to transparency mode based upon LPRng queue alias ('qq' printcap option). Here's out printcap entry for the Phaser 450, using our filter: # Tektronix Phaser 450-2 phaser450-2|phaser450-2t|phaser440|phaser440t :lp=/dev/null:qq :af=acct:lf=log:fx=flpv:sh:mx#0:ps=status :if=/usr/local/lib/filters/phaserif :sd=/var/spool/lpd/phaser450-2 Attached is the Perl filter I wrote that has been very slightly modified since its inception by Al Marquardt. It's written with Solaris in mind and is perhaps a little crude, but it works quite well for us. Feel free to modify/use it in any way you like- direct any and all comments to Al Marquardt (almar@uiuc.edu). -- Russ Thacher Systems Administrator, UIUC Bioacoustics Research Lab -------------- Filter ----------------- #!/usr/local/bin/perl5 use Getopt::Std; use Socket; use Sys::Hostname; pop @ARGV; # Get all the filter options LPRng knows getopts('a:b:cd:e:f:h:i:j:k:l:m:n:p:r:s:t:w:x:y:F:P:S:C:H:A:J:L:Q:'); # set default exit status (JFAIL) $! = 1; # Set default error messages $udpsockerr = "ERROR: Cannot establish UDP socket: $!\n"; $udpbinderr = "ERROR: Cannot bind to UDP socket: $!\n"; $udpsenderr = "ERROR: Cannot send UDP status request: !$\n"; $udprecverr = "ERROR: Cannot receive UDP status report: !$\n"; $tcpsockerr = "ERROR: Cannot establish TCP socket: $!\n"; $tcpconnecterr = "ERROR: Cannot connect to TCP socket: $!\n"; $tcpcloseerr = "ERROR: Cannot close TCP socket: $!\n"; # Get current time/date @MONTHS = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $month = $MONTHS[$mon]; if (length($sec) == 1) { $sec = "0$sec" } if (length($min) == 1) { $min = "0$min" } if (length($hour) == 1) { $hour= "0$hour" } if (length($mday) == 1) { $mday= " $mday" } $datestamp = "$month $mday $hour:$min:$sec"; # Write a 'job begin' line to printer log file print STDERR "START: job number $opt_j (dfile: $opt_e) for $opt_n\@$opt_h on $opt_P at $datestamp\n"; # Setup network info for printers $phaser4501 = 'phaser450-1'; $phaser4502 = 'phaser440'; $udpport = '9101'; $tcpport = '9100'; # Setting up UDP socket info so we can get status reports from phasers... $myip = gethostbyname(hostname()); $udpproto = getprotobyname('udp'); $myudppaddr = sockaddr_in(0, $myip); if ($opt_P eq 'phaser450-1') { $printip = inet_aton($phaser4501); } elsif ($opt_P eq 'phaser450-2') { $printip = inet_aton($phaser4502); } $printudppaddr = sockaddr_in($udpport, $printip); socket(UDPSOCK, PF_INET, SOCK_DGRAM, $udpproto) or die $udpsockerr; bind(UDPSOCK, $myudppaddr) or die $udpbinderr; # Setting up TCP socket info so we can send jobs to the printer # and read pagecounts $tcpproto = getprotobyname('tcp'); $mytcppaddr = sockaddr_in(0, $myip); $printtcppaddr = sockaddr_in($tcpport, $printip); socket(TCPSOCK, PF_INET, SOCK_STREAM, $tcpproto) or die $tcpsockerr; setsockopt(TCPSOCK, SOL_SOCKET, SO_KEEPALIVE, 0); setsockopt(TCPSOCK, SOL_SOCKET, SO_LINGER, 0); # Before any printing check to be sure printer is idle # If it's not, check every 5 seconds until it is defined(send(UDPSOCK, "\r\n", 0, $printudppaddr)) or die $udpsenderr; $udpout = ""; ($printudppaddr = recv(UDPSOCK, $udpout, 100, 0)) or die $udprecverr; $realudpout = unpack("a*", $udpout); while ($realudpout ne 'status: idle') { print STDERR "$opt_P not at idle status. Cannot start print job.\n"; defined(send(UDPSOCK, "\r\n", 0, $printudppaddr)) or die $udpsenderr; $udpout = ""; ($printudppaddr = recv(UDPSOCK, $udpout, 100, 0)) or die $udprecverr; $realudpout = unpack("a*", $udpout); sleep 5; } # Get the initial page count connect(TCPSOCK, $printtcppaddr) or die $tcpconnecterr; select TCPSOCK; $| = 1; select STDOUT; print TCPSOCK "%!\n"; print TCPSOCK "(%%\[ pagecount: )print statusdict /pagecount get exec "; print TCPSOCK "( )cvs print "; print TCPSOCK "( \]%%) = flush\n"; $tcpout = ; if ($tcpout =~ /%%\[ pagecount:.*/) { @tcparray = split /\s/, $tcpout; $pagecount1 = $tcparray[2]; } # Get current time/date (again, this time for the accounting file) ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $month = $MONTHS[$mon]; if (length($sec) == 1) { $sec = "0$sec" } if (length($min) == 1) { $min = "0$min" } if (length($hour) == 1) { $hour= "0$hour" } if (length($mday) == 1) { $mday= " $mday" } $datestamp = "$month $mday $hour:$min:$sec"; # open LPRng accounting file if( defined( $opt_a ) && $opt_a && open ACCT, ">>$opt_a" ){ print ACCT "DEBUG: printer return string= $tcpout"; print ACCT "start -p'$pagecount1' -q'$opt_j' -J'$opt_J' -k'$opt_k'" . "-n'$opt_n' -h'$opt_h' -P'$opt_P' -F'$opt_F' -t'$datestamp'\n"; close ACCT; } # Start shoving data out to printer # Set print/transparency by queue name if ($opt_Q =~ /.*t/) { print TCPSOCK "%!\n"; print TCPSOCK "mark\n"; print TCPSOCK "{\n"; print TCPSOCK " 3 dict begin\n"; print TCPSOCK " /MediaType null def\n"; print TCPSOCK " /MediaColor (Transparent) def\n"; print TCPSOCK " currentdict end setpagedevice\n"; print TCPSOCK "} stopped cleartomark\n"; } # Shove the rest of the data file out to the printer while ($line = ) { print TCPSOCK $line; } close TCPSOCK or die $tcpcloseerr; # Listen for 'status:idle' from printer- this signifies that job is done and # we can ask printer for page count # we wait until 'status:idle' is received- retrying every 3 seconds $realudpout = ""; while ($realudpout ne 'status: idle') { defined(send(UDPSOCK, "\r\n", 0, $printudppaddr)) or die $udpsenderr; $udpout = ""; ($printudppaddr = recv(UDPSOCK, $udpout, 100, 0)) or die $udprecverr; $realudpout = unpack("a*", $udpout); sleep 2; } # Now we're ready to grab the final page count from the printer socket(TCPSOCK, PF_INET, SOCK_STREAM, $tcpproto) or die $tcpsockerr; connect(TCPSOCK, $printtcppaddr) or die $tcpconnecterr; print TCPSOCK "%!\n"; print TCPSOCK "(%%\[ pagecount: )print statusdict /pagecount get exec "; print TCPSOCK "( )cvs print "; print TCPSOCK "( \]%%) = flush\n"; $tcpout = ; if ($tcpout =~ /%%\[ pagecount:.*/) { @tcparray = split /\s/, $tcpout; $pagecount2 = $tcparray[2]; } close TCPSOCK or die $tcpcloseerr; # Get date/time again ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $month = $MONTHS[$mon]; if (length($sec) == 1) { $sec = "0$sec" } if (length($min) == 1) { $min = "0$min" } if (length($hour) == 1) { $hour= "0$hour" } if (length($mday) == 1) { $mday= " $mday" } $datestamp = "$month $mday $hour:$min:$sec"; # Update accounting file upon close $pages = $pagecount2 - $pagecount1; if( defined( $opt_a ) && $opt_a && open ACCT, ">>$opt_a" ){ print ACCT "DEBUG: printer return string= $tcpout"; print ACCT "end -b'$pages' -p'$pagecount2' -q'$opt_j' -J'$opt_J'" . "-k'$opt_k' -n'$opt_n' -h'$opt_h' -P'$opt_P' -F'o' -t'$datestamp'\n"; close ACCT; } # Write a 'Job End' line to the printer log print STDERR "END: job number $opt_j (dfile: $opt_e) " . "for $opt_n\@$opt_h on $opt_P at $datestamp\n\n"; 44..2222.. DDuupplleexx PPrriinnttiinngg Duplex printing is when you print on both sides of a page. Some printers which do duplex printing require that you send them special commands to force this mode. This is usually done by the FILTERS. The IFHP filter makes a stab at sending the PJL or PostScript commands to the printer. Many people have reported problems doing duplex printing, so here is a check list. 1. Make sure you have enough memory for the worst case print job. Usually the printer has to rasterize both pages before it can produce an impression. It may require much more memory than you expect. 2. Check your printer manual to discover the EXACT form of the enter duplex mode command and make sure that either the command is part of the job (PJL language at the start of the job, postscript header, etc), or that the filter generates the correct form. Note there is a PostScript Printer Description file (PPD) for most printers that support PostScript, and they even have the PJL and PostScript code for this in the PPD file. 3. It has been observed that even with what would apparently be sufficient memory, that many duplex jobs print 'oddly', that they are not aligned on the same side in the same way, etc etc. This may not be the fault of the software, but of the support for duplex operation. 4. Read the IFHP documentation, and create a configuration section in the ifhp.conf file for your printer. I know this is painful, but until there is a uniform way to get the correct commands extracted from either PPD or some other database then this appears to be the only way to do it. _P_a_t_r_i_c_k _P_o_w_e_l_l 44..2233.. TTeesstt VVeerrssiioonn aanndd PPoorrttaabbiilliittyy TTeessttiinngg The LPRng code has the ability to run as non-setuid software, and to use the non-default TCP/IP ports for communication. This facility allows a _T_e_s_t _V_e_r_s_i_o_n to be run in parallel with the normal LPRng software. To simplify testing and portability issues, a simple test version of the spool queues and jobs has been supplied with the LPRng distribution. These queues can be placed in a suitable location (/tmp is common) and the LPRng software tested. The test version of the software will use the LPD_CONF environment variable to specify the location of the configuration file. It will read this configuration file on startup and use the values to override the normal defaults. Since a user could maliciously set up their own configuration files with values that could compromise system security, it is strongly recommended that the test version is not made SETUID root. In fact, the LPRng code will chatter messages when the LPD_CONF ability is enabled and it is run as root. 44..2233..11.. CCoommppiilliinngg tthhee TTeesstt VVeerrssiioonn Edit src/Makefile, and uncomment the indicated line. Then run make to regenerate the distribution. #### ****** TESTING AND SECURITY LOOPHOLE ****************************** # Define GETENV to allow the LPD_CONFIG environment # variable to be used as the name of a configuration file. In non-testing # systems, this is a security loophole. #CF := $(CF) -DGETENV 44..2233..22.. SSeettttiinngg UUpp TThhee TTeesstt VVeerrssiioonn SSppooooll QQuueeuueess The LPRng TESTSUPPORT directory contains a set of shell scripts and files that need to be installed in the appropriate directory. The following steps are used. 1. First, you need to set up your HOST environment variable to the fully qualified domain name of your host and your USER environment variable to your user name. This is done in order to get values to put into the Test Version configuration files. 2. In the TESTSUPPORT directory, edit the Makefile, and specify the location of the Test Version spool queues. The default location is /tmp; since on most systems these files are deleted or are available to everybody, a more secure location should most likely be used. DDOO NNOOTT UUSSEE TTHHEE RRAAWW TTEESSTTFFIILLEE DDIIRREECCTTOORRYY. These files need to be copied and placed in another directory. 3. The LPD_CONF environment variable should be set to the location of the installed lpd.conf file. 4. In the TESTSUPPORT directory, run make. This will copy and install the necessary files. Example: CSH: setenv HOST {fully qualified domain name}; setenv USER `whoami` setenv LPD_CONF /tmp/LPD/lpd.conf set path=( /tmp/LPD $path ) unsetenv PRINTER Example: setenv HOST astart1.astart.com setenv USER papowell setenv LPD_CONF /tmp/LPD/lpd.conf set path=( /tmp/LPD $path ) unsetenv PRINTER Bourne Shell: HOST={fully qualified domain name}; export HOST; USER='whoami'; export USER LPD_CONF=/tmp/LPD/lpd.conf.$HOST; export LPD_CONF PATH=/tmp/LPD:$PATH; export PATH PRINTER=; export PRINTER Example: HOST=astart1.astart.com; export HOST USER=papowell; export USER LPD_CONF=/tmp/LPD/lpd.conf.$HOST; export LPD_CONF PATH=/tmp/LPD:$PATH; export PATH PRINTER=; export PRINTER cd TESTSUPPORT make 44..2233..33.. RRuunnnniinngg tthhee TTeesstt VVeerrssiioonn SSooffttwwaarree Set your current directory to the location of the compiled Test Version executables. Execute the various executables using ./cmd, or set . aass tthhee ffiirrsstt eennttrryy iinn tthhee PPAATTHH . If it is not the first entry, then the standard system executables will be used. 1. Run ./checkpc. this will print out the various values for the spool queues in the Test Version setup. If the t1, t2,... spool queues are not displayed, make sure that the LPD_CONF environment variable is set correctly and that you are using the Test Version executable. 2. Run ./checkpc -f. This will fix up the (deliberately introduced) problems in the spool queues. 3. Next, run ./lpd -F in one window, and then run ./lpq -a in another window. This will check that the server is working. 4. You can now amuse yourself by sending jobs, setting up permissions checking, and other chores. 5. When everything appears to be working correctly, you can then remove the Test Version flag from the src/Makefile, recompile, and install the LPRng software. 44..2233..44.. PPoorrttaabbiilliittyy TTeessttiinngg You should ignore the information in this section UNLESS you are trying to do a port to a new or whacko version of a UNIX system. LPRng has been tested on just about every version of UNIX that supports POSIX capabilities, and if it is having problems then most likely it is due to non-portability issues. However, if you feel that your system is not POSIX compatible, or you are having serious problems due to LPRng's use of the system facilities, feel free to try the following tests. Needless to say, if you identify problems, please inform the developers and they will most likely assist you in resolving them. Set your current directory to the location of the compiled Test Version executables. Execute the various executables using ./cmd, or set . aass tthhee ffiirrsstt eennttrryy iinn tthhee PPAATTHH . If it is not the first entry, then the standard system executables will be used. 1. Run ./checkpc -T /tmp/a. This will perform a limited set of tests of the LPRng functionality. Note that some of them will fail as checkpc is not running SUID ROOT and the /tmp/a is not a serial device. ALL of the non-SUID related messages should indicate success. 2. Set checkpc to setuid ROOT, and then rerun the tests. chown root checkpc chmod u+s checkpc ./checkpc -T /tmp/a The SETUID tests should now succeed. If they do not, then you have a VERY odd UNIX system, and you are on your own on this one. See the comments in src/common/setuid.c for help. 3. Now run tests for serial line control and locking: ./checkpc -T /dev/ttya # or an appropriate UNUSED tty device You most likely will have to attach a terminal or modem to the serial device in order to cause the open() to succeed, as most serial device drivers block when DSR is not enabled. Check the messages concerning the stty actions. Make sure that the appropriate changes have taken place. You may get errors about _d_e_v_i_c_e _l_o_c_k failing. This is due to whacko differences in the ways that different UNIX systems (or versions of the same UNIX system) implement serial device locking. My advice is to ignore this problem unless you INSIST on having multiple users of the same serial printing port, in which case you are asking for serious trouble, and you are on your own. I am not interested in patches or queries on problems on serial device locking problems. In fact, this facility is only used if the lk printcap flag is TRUE (default FALSE). 55.. //eettcc//pprriinnttccaapp PPrriinntt SSppooooll DDaattaabbaassee FFiillee The heart of the LPRng system is the file /etc/printcap. This file contains a list of printer definitions. I'll describe a few simple configurations. I would advise you to read through all of them, as I will introduce several features gradually throughout this section. For details about individual printcap items, see the printcap(5) man page from the LPRng distribution, or entries in the ``index'' section. 55..11.. IInnddeexx TToo AAllll TThhee OOppttiioonnss 55..22.. AA vveerryy ssiimmppllee eexxaammppllee Options used: +o cm=_c_o_m_m_e_n_t _f_o_r _s_t_a_t_u_s +o if=_d_e_f_a_u_l_t _j_o_b _f_i_l_e _f_i_l_t_e_r +o lf=_l_o_g _f_i_l_e +o mx#_m_a_x_i_m_u_m _j_o_b _s_i_z_e +o lp=_o_u_t_p_u_t _d_e_v_i_c_e +o sd=_s_p_o_o_l _d_i_r_e_c_t_o_r_y _f_i_l_e +o sh _s_u_p_p_r_e_s_s _h_e_a_d_e_r_s _(_b_a_n_n_e_r_s_) +o sf _s_u_p_p_r_e_s_s _f_o_r_m _f_e_e_d_s _b_e_t_w_e_e_n _f_i_l_e_s The easiest configuration is this: a local printer directly connected to a printer port. # Local ASCII printer lp1|printer # alias is printer or lp |lp :lp=/dev/lp1 :cm=Dumb printer :sd=/var/spool/lpd/lp1 :lf=log:af=acct :if=/usr/local/sbin/lpf :mx#0:sh:sf Option Meaning ``ab'' always print banner, ignore lpr -h option ``achk'' query accounting server when connected ``ae'' accounting at end (see also af, la, ar, as) ``af'' name of accounting file (see also la, ar) ``ah'' automatically hold all jobs ``allow_duplicate_args'' Allow duplicate command line arguments (legacy requirement) ``allow_getenv'' Allow use of LPD_CONF ``allow_user_logging'' allow users to request logging info using lpr -mhost%port ``ar'' enable remote transfer accounting (if af is set) ``as'' accounting at start (see also af, la, ar) ``use_auth'' authentication type to use ``auth_client_filter'' client to server authentication transfer program ``auth_forward'' server to server authentication method ``auth_forward_filter'' server to server authentication transfer program ``auth_receive_filter'' server receive authentication program ``auth_server_id'' server id for authentication ``be'' Banner at End Generation Program ``bk'' Berkeley LPD job file format ``bk_filter_options'' Berkeley LPD filter options ``bk_of_filter_options'' Berkeley LPD OF filter options ``bkf'' backwards-compatible filters: use simple paramters ``bl'' short banner line sent to banner printer ``bp'' Banner Generation Program (see bs, be) ``bq'' Use filters on bounce queue jobs ``bq_format'' Format of bounce queue output ``br'' Serial port bit rate (see ty) ``bs'' Banner at Start Generation Program ``cd'' control directory ``check_for_nonprintable'' LPR checks for nonprintable file ``check_idle'' program used to check for idle printer ``class_in_status'' Show job class name in lpq status information ``cm'' comment identifying printer (LPQ) ``config_file'' configuration file ``connect_grace'' connection control for remote printers ``connect_interval'' connection control for remote printers ``connect_timeout'' connection control for remote printers ``connect_try'' connection control for remote printers ``control_filter'' control file filter ``db'' debug options for queue ``default_format'' default job format ``default_permission'' default permission for files ``default_printer'' default printer ``default_priority'' default job priority ``default_remote_host'' default remote host ``default_tmp_dir'' default directory for temp files ``destinations'' printers that a route filter may return and we should query ``fc'' OBSOLETE, see sy ``fd'' forwarded jobs not accepted ``ff'' string to send for a form feed ``filter_ld_path'' filter LD_LIBRARY_PATH value ``filter_options'' filter options ``filter_path'' filter PATH environment variable ``filter_poll'' interval to check for OF filter output ``fo'' send form feed when device is opened ``force_fqdn_hostname'' force FQDN HOST value in control file ``force_localhost'' force clients to send all requests to localhost ``force_queuename'' force use of this queuename if none provided ``fq'' send form feed when device is closed ``fs'' OBSOLETE (see sy) ``full_time'' use extended time format ``fx'' valid output filter formats ``group'' Effective Group ID (EGID) for SUID ROOT programs ``hl'' Header (banner) last, at end of job Ignore control file and data file name format errors |``ignore_requested_user_priority'' | Ignore requested user priority | |``if'' | default (f, l) filter program | |``ipv6'' | using IPV6 conventions | |``kerberos_keytab'' | kerberos keytab file location | |``kerberos_life'' | kerberos key lifetime | |``kerberos_renew'' | kerberos key renewal time | |``kerberos_forward_principal'' | kerberos remote principle name for forwarding | |``kerberos_server_principal'' | kerberos remote server principle name | |``kerberos_service'' | kerberos default service | |``la'' | enable local printer accounting (if af is set) | |``ld'' | leader string sent on printer open | |``lf'' | error log file for spool queue | |``lk'' | lock the IO device | |``lockfile'' | lpd lock file | |``logger_destination'' | destination for logging information | |``logger_timeout'' | intervals between connection attempts | |``logger_pathname'' | temp file for log information | |``logger_max_size'' | max size in Kbytes of temp file for log information | |``longnumber'' | use long job number when a job is submitted | |``lp'' | printer device name or specification | |``lpd_bounce'' | force lpd to filter job before forwarding | |``lpd_force_poll'' | force lpd to poll idle printers | |``lpd_poll_time'' | interval between lpd printer polls | |``lpd_port'' | lpd listening port | |``lpd_printcap_path'' | lpd printcap path | |``lpr_bounce'' | lpr does filtering as in bounce queue | |``lpr_bsd'' | lpr does filtering as in bounce queue | I'll use this simple example to explain the basics of the LPRng printcap format. Lines starting with a # sign are comments, and all leading and trailing _w_h_i_t_e_s_p_a_c_e, i.e. - spaces, tabs, etc, are ignored. Empty lines are ignored as well. Note that you are not required to use continuation backslashes (\) as would be needed for an BSD LPR style printcap file in the printcap entries. You are allowed to use them, however: this comes in handy if you happen to have a BSD LPR printcap file. The backslash will cause the next line to be appended to the current line; watch out for comments and ends of printcap entries if you use this. A printer (printcap entry) definition starts with the printer _n_a_m_e, followed by one or more _a_l_i_a_s_e_s, followed by a list of options. The name for a printer will be used be in LPRng status output to identify the printer. The colon (:) is used to start the definition of an option or flag values. The definition continues to the end of the line or until the next colon. If an option value contains a colon, then use \: to escape the value. Options take the form of a keyword/value pair. Options and values are case sensitive; for example Ts and ts refer to different options. Numerical values are indicated by a # separator, while a = indicates a string value. Boolean switches or flags are set TRUE if no value follows the keyword and FALSE by appending a @. For example sh will set the sh flag to TRUE and sh@ to FALSE. There may be several options on the same line, separated by colons. However, this does make the file less readable. The next tip was supplied by James H. Young : My personal preference for readability is to always put each option on its own line. Putting each option on its own line is worth the trouble even though it detracts from the usability of certain grepping techniques when trying to ``mail_from'' mail user from user name ``mail_operator_on_error'' mail to this operator on error ``max_connect_interval'' maximum time between connection attempts ``max_log_file_size'' maximum size (in K) of spool queue log file ``max_servers_active'' maximum number of lpd queue servers that can be active ``max_status_line'' maximum length of status line ``max_status_size'' maximum size (in K) of status file ``mc'' maximum copies allowed ``min_log_file_size'' minimum size (in K) of spool queue log file ``min_status_size'' minimum size to reduce status file to ``minfree'' minimum amount of free space needed ``ml'' minimum number of printable characters for printable check ``ms_time_resolution'' millisecond time resolution ``mx'' maximum job size (1Kb blocks, 0 = unlimited) ``nb'' use nonblocking device open ``network_connect_grace'' pause between transferring jobs to remote printer ``of'' banner output filter ``of_filter_options'' OF filter options ``originate_port'' originate connections from these ports ``pass_env'' clients pass these environment variables to filters ``perms_path'' lpd.perms files ``pl'' page length (in lines) ``pr'' pr program for p format ``printcap_path'' /etc/printcap files ``ps'' printer status file name ``pw'' page width (in characters) ``px'' page width in pixels (horizontal) ``py'' page length in pixels (vertical) ``qq'' put queue name in control file ``remote_support'' operations allowed to remote host ``report_server_as'' server name for status reports ``retry_econnrefused'' Retry on connect ECONNREFUSED errors ``retry_nolink'' Retry device open or connect failures ``return_short_status'' return short lpq status when request arrives from specified host ``reuse_addr'' set SO_REUSEADDR on outgoing ports ``reverse_lpq_format'' reverse lpq format when request arrives from specified host ``rg'' clients allow only users in this group access to printer ``rm'' remote machine (hostname) (with rp) ``router'' routing filter, returns destinations ``rp'' remote printer name (with rm) ``rw'' open printer for reading and writing ``safe_chars'' additional safe characters in control file lines ``save_on_error'' save job when an error ``save_when_done'' save job when done ``sb'' short banner (one line only) ``sd'' spool directory pathname ``send_block_format'' send block of data, rather than individual files ``send_data_first'' send data files first in job transfer ``send_failure_action'' failure action to take after send_try attempts failed ``send_job_rw_timeout'' print job read/write timeout ``send_query_rw_timeout'' status query operation read/write timeout ``send_try'' maximum number of times to try sending job ``sendmail'' sendmail program ``server_tmp_dir'' server temporary file directory ``sf'' suppress form feeds separating data files in job ``sh'' suppress header (banner) pages ``short_status_length'' short lpq status length in lines ``socket_linger'' set the SO_LINGER socket option ``spool_dir_perms'' spool directory permissions ``spool_file_perms'' spool file permissions ``spread_jobs'' amount to spread jobs to avoid collisions ``ss'' name of queue that server serves (with sv) ``stalled_time'' time after which to report active job stalled ``stop_on_abort'' stop processing queue on filter abort ``stty'' stty commands to set output line characteristictics |``sv'' | names of servers for queue (with ss) | |``syslog_device'' | name of syslog device | |``tr'' | trailer string to send before closing printer | |``translate_format'' | translate data format in control file | |``use_date'' | force date in control file | |``use_identifier'' | force identifier in control file | |``use_info_cache'' | read and cache information | |``use_queuename'' | put queue name in control file (alias for qq) | |``use_shorthost'' | Use short hostname for lpr control and data file names | |``user'' | Effective User ID (EUID) for SUID ROOT programs | |``xc'' | OBSOLETE (see sy) | |``xs'' | OBSOLETE (see ty) | |``xt'' | formats supported on printer | maintain these types of files. Let's go over the options used in this example: 1. First of all, there's the lp entry. It specifies the file (or location) to which data is sent. Here, it is the device /dev/lp1. (This is system-dependent---check your vendor's manual for information on devices.) The absolute pathname indicates we have a local printer or file. 2. The cm field can be used to supply a comment to be used as a header in lpq output. 3. sd specifies the spool directory. This is where files are stored until they are printed. 4. The lf and af options specify the location for the log and accounting files, respectively. They are not strictly needed for the printer to function, but a log file is highly recommended, in case things go wrong. One special point to note: if these files don't exist, they will not be created, and no logging or accounting will be done. You will need to create them manually (e.g., by using touch) or by using the `` checkpc'' program. LPRng is very fussy about permissions - you should run cchheecckkppcc to make sure that the log and status files have the correct ownership and permissions. 5. The if entry specifies a `filter' for the `text' format. The filter will be applied to any incoming job (of a certain format), even the ones coming from another host. Filters and print formats are discussed in section ``Filters''. This particular filter would translate UNIX LF line endings to DOS CR/LF, to prevent the `staircase effect' and expand tabs to spaces. As this problem also occurs with other printing daemons, it is likely that your system has a similar utility. 6. mx indicates the maximum file size for a print job. Supplying 0 here means that there is no limit. 7. Finally, I have given the sh (suppress headers) flag. This will inhibit banner pages. 55..33.. AA sseerriiaall pprriinntteerr qquueeuuee Options used: +o br#_s_e_r_i_a_l _p_o_r_t _b_i_t _r_a_t_e +o stty=_s_t_t_y _o_p_t_i_o_n_s _f_o_r _s_e_r_i_a_l _p_o_r_t _c_o_n_f_i_g_u_r_a_t_i_o_n When connecting to a serial printer, you need to set up the serial line so that it will pass data without any additional processing. This will allow binary files to be transferred safely. The sy printcap entry specifies a set of stty(1) flags and line speed that will be used to set up the serial line. (See ``Serial Printers'' for details) The br (bit rate) option can be used to specify the line speed as well. The following is a typical printcap for a serial printer. # Local Serial ASCII printer lp2 :lp=/dev/ttya :cm=Serial printer :sd=/var/spool/lpd/lp2 :stty=9600 -echo -crmod -raw -oddp -evenp pass8 cbreak ixon :if=/usr/local/sbin/lpf :mx#0:sh 55..44.. AA rreemmoottee pprriinntteerr qquueeuuee Options used: +o lp=_d_e_s_t_i_n_a_t_i_o_n +o rm=_r_e_m_o_t_e _h_o_s_t _(_m_a_c_h_i_n_e_) +o rp=_r_e_m_o_t_e _p_r_i_n_t_e_r _(_m_a_c_h_i_n_e_) LPRng will allow you to print over a TCP/IP network, just like the BSD LPR software. The machine from which you are printing is called the llooccaall or cclliieenntt host. You run the lpr program on the client host to send print jobs to the lpd daemon or server process running on the remote sseerrvveerr host. The lpd daemon accepts jobs for printing, puts them in its print queue, and processes them for printing on a printer. This operation of having a user (client) program send requests or jobs to another (server) program which does the actual work is called the client/server model of computing. The lpd daemon process is the server, and the lpr, lpq, lprm, and lpc are client programs. The clients send either jobs or service requests to the server using the ``RFC1179'' protocol. One of the major ways that LPRng differs from the BSD LPD software is that the client programs are vastly more powerful and flexible. The BSD LPR software client programs transferred print jobs to spool (queue) directories on the client's host machine; the lpd server running on the client machine would then take these files and transfer them to the remote lpd server. This meant that every host was required to run an lpd daemon process and to have spool queues for every printer that the user could possibly use. Imagine the problems that exist in a facility with literally thousands of printers, many of which are being added or removed from service on a daily basis. This would require the system administrators to create spool directories on each host. The LPRng software eliminates these problems by allowing client programs to directly transfer jobs to a remote lpd daemon or printer over a TCP/IP network connection. This eliminates both the need for a lpd daemon as well as the print spool directories on the local host. To send a job to a printer or remote `lpd' daemon all you need to do is specify the printer name and server hostname or IP address. This can be done using: lpr -Ppr@server printfile This will cause the lpr program to transfer the printfile to the lpd daemon running on the server host, and spool it for the pr printer. If you set the PRINTER environment variable, then you can simply do the following: PRINTER=pr@server; export PRINTER; lpr printfile 55..55.. NNeettwwoorrkk PPrriinnttiinngg WWiitthh //eettcc//pprriinnttccaapp While the above method is the simplest way to use the LPRng software for network printing, some users discover that they need the full power of a lpd server running on their local host to support printing, or need more than the simple transfer and network capabilities of the client programs. Another problem is that they sometimes need to have _a_l_i_a_s_e_s for their printer names, or want to be able to specify just the name of the printer and have the remote server for it supplied by the printing software. This type of operation requires setting up an /etc/printcap file and using the printcap configuration information. Both the client programs (lpr, lpc, lprm, lpq) and the lpd daemon use the information in the /etc/printcap file to specify how they will process print jobs. The same printcap file is used by both client programs and the lpd daemon, but each will use different parts of the information. There are several possibilities for specifying network printers. _I_'_m _s_h_o_w_i_n_g _s_o_m_e _d_i_f_f_e_r_e_n_t _s_y_n_t_a_x_e_s _f_o_r _t_h_e _e_n_t_r_i_e_s _h_e_r_e_. _T_h_i_s _i_s _t_h_e _i_n_f_o_r_m_a_t_i_o_n _t_h_a_t _c_l_i_e_n_t_s _w_i_l_l _n_e_e_d _t_o _h_a_v_e _t_o _s_e_n_d _a _j_o_b _t_o _t_h_e _n_e_t_w_o_r_k _p_r_i_n_t_e_r_. # This is LPRng specific remote|Remote Printer :lp=raw@server # Convention from `old' BSD spooler remote:Old Format:\ :rp=raw:rm=server # Sometimes you have to connect to a non-standard port special:lp=lp@server%2000 All the above printcap entries will make the lpr print client connect to the remote host server and send the file to the raw printer. You can specify the remote printer and remote host using the :rp and :rm entries, or the LPRng extension lp=rp@rm. Note that we don't need a spool directory for this kind of printer, nor do we need to run lpd on the client host machine, as the job will be transferred directly to the remote host. Many printers now come equipped with a network support card that has a built in LPD print spooler. If this is the case you can print directly to the printer and do not need to spool your print job to a server. 55..66.. SSppoooolliinngg TToo LLooccaall SSeerrvveerr Options used: +o force_localhost _f_o_r_c_e _c_l_i_e_n_t_s _t_o _s_e_n_d _r_e_q_u_e_s_t_s _t_o _l_o_c_a_l_h_o_s_t Some users may not want to send a print job directly to a remote printer. The printer may need the more powerful management functions of a print spooler to handle problems such as paper feed errors, multiple users, etc, or needs to run special ``filters'' to process the print job. In this case, they want the print job sent to a lpd server on the local host, which in turn will spool the job and send it to the remote printer. This can be done in several ways. # Method 1: force client transfer to localhost # have server send to real printer # both client and server will see the following information remote|Spool to localhost :lp=lp@localhost # Note that only the server will see the following information lp:server:lp=lp@remote:sd=/usr/spool/lp # Method 2: force client transfer to localhost # both client and server will see the following information remote|Spool to localhost :force_localhost :lp=lp@remote:sd=/usr/spool/lp # Method 3: force a bounce queue with no effect remote|Spool to localhost :lp=lp@localhost :bq=lp@remote:sd=/usr/spool/lp In the first method, we have the clients send jobs to the lp printer on the localhost; localhost is the 'canonical' network name for the host on which the program is running. The lpd server on the localhost will get the print job, store it in the spool directory /usr/spool/lp and then forward the job to the lp printer on the remote host. The server tag indicates that a printcap entry is to be used only by the lpd daemon (server) process, and the information is ignored by the client. The server tag is discussed in detail in the ``Shared printcap files'' section. One of the problems is finding the name of the local host. On some implementations which are not using a Domain Name Server, it is necessary to specify the local host name by using the localhost configuration variable. The second method is slightly different. The force_localhost flag has meaning only for the client application programs, and forces them to send the job to the localhost. The server will then send the job to the remote host. The third method is useful when you want the print job to be modified _e_n _p_a_s_s_a_n_t as it passes through the spool queue. See the ``Filters'' discussion for details. 55..77.. SShhaarreedd pprriinnttccaapp ffiilleess When both the client host and server host are the same machine, then the same /etc/printcap file will be used by both the lpr and lpd daemon programs. When LPRng programs read the /etc/printcap file, they accumulate information in the printcap file on individual printer entries. For example, the following printcap entries would result in the indicated information: #/etc/printcap file pr:lp=pr@host pr:lp=/dev/lp:sh #resulting printcap information: pr:lp=/dev/lp:sh This allows us to split up the printcap information into different blocks, and has been used to manage complex printcap entries on large sites with many printers. We can use the server tag to specify that specific printcap information is only for use by the lpd daemon. For example: #/etc/printcap file pr:lp=pr@host pr:server:lp=/dev/lp:sh #resulting printcap information for client pr:lp=pr@host #resulting printcap information for lpd daemon pr:lp=/dev/lp:sh Many administrators at large sites will split up their printcap files so that the information needed to tell clients where the servers are for a printer is located at the start of the /etc/printcap file, and the actual information needed by the lpd daemon is at the end. Here is a sample: #/etc/printcap file pr1:lp=pr1@serverhost pr2:lp=pr2@serverhost pr1:server:lp=/dev/lp:tc=.common pr2:server:lp=/dev/lp:tc=.common .common:sd=/usr/local/lpd/%P :cm=Dumb printer %P :lf=log:af=acct :if=/usr/local/sbin/lpf :mx#0:sh This printcap entry also shows the use of the tc option, which corresponds to the C Compiler Preprocessor (cpp) #include directive. Printcap entries starting with periods, underscores (_), or @ signs are treated as dummy printcap information and can only be referenced by the tc. When the printcap information is read, the LPRng code will substitute the cannonical printer name for any %P tokens that it finds in the printcap. After processing the information in the printcap entry, the clients and lpd daemon will see the following: # clients pr1:lp=pr1@serverhost pr2:lp=pr2@serverhost # server pr1:lp=/dev/lp :sd=/usr/local/lpd/pr1 :cm=Dumb printer pr1 :lf=log:af=acct :if=/usr/local/sbin/lpf :mx#0:sh pr2:server:lp=/dev/lp: :sd=/usr/local/lpd/pr2 :cm=Dumb printer pr2 :lf=log:af=acct :if=/usr/local/sbin/lpf :mx#0:sh 55..88.. MMaasstteerr PPrriinnttccaapp FFiilleess One of the major problems faced by administrators of large sites is how to distribute printcap information. They would like to have a single printcap file either distributed by a file server (NFS) or by some other method such as rdist. By using the server tag, information for the lpd daemons can be separated out from the information needed by the lpr print client. The oh=pattern specifies that this information is only to be used by a specified host. For example: #/etc/printcap file pr1:lp=pr1@serverhost1:oh=*.eng.site.com,130.191.12.0/24 pr2:lp=pr1@serverhost1:oh=*.eng.site.com,130.191.12.0/24 pr1:lp=pr2@serverhost2:oh=*.admin.site.com pr2:lp=pr2@serverhost2:oh=*.admin.site.com pr1:server:oh=serverhost1.eng.com:lp=/dev/lp:tc=.common pr2:server:oh=serverhost2.admin.com:lp=/dev/lp:tc=.common .common:sd=/usr/local/lpd/%P The above example is a total abuse of the use of oh tag, but has some interesting effects. The pattern is used as a _g_l_o_b pattern and is applied to the fully qualified domain name (FQDN) of the host reading the printcap file. For example, *.eng.site.com would match host h1.eng.site.com but would not match h1.admin.site.com. Thus, the effects of the first couple of entries would be to specify that the pr1 and pr2 printers on the eng hosts would be pr1@serverhost1, and on the admin hosts would be pr2@serverhost2, Also, the lpd daemons on serverhost1 and serverhost2 would only extract the additional information for pr1 and pr2 respectively. You can also specify network addresses and subnet masks as well. In this case, if the host matches the network address then it will use the information. 55..99.. PPrriinnttccaapp ooppttiioonnss ffoorr llpprr,, llppqq,, llpprrmm,, aanndd llppcc These programs are used by users to connect to the lpd server and send print jobs or a request. For details about the way that this is done, see ``LPRng and RFC1179'' for details. The following options and configuration variables are used by the various programs to control how they will generate jobs and send them to the server. 55..99..11.. llpp,, rrmm aanndd rrpp The rm (remote machine or host) and rp or lp printer printcap options are used to specify the remote host and printer to be used. These values can be extracted from a printcap entry, or supplied in the following manner. 1. If the user program is invoked with -Pxxx argument, then the lp option is assigned the value xxx. 2. If no explicit value is specified and the PRINTER environment variable has value xxx, then the lp option is assigned value xxx. 3. If lp has a value of the form rp@rm or rp@rm%port, then the rp, rm, and lpd_port options are assigned the indicated values. 4. If rm or rp does not have a value, then they are assigned the default_host (usually localhost) and default_printer (usually lp) option values. 5. A connection is made to lpd_port on host rm and the file transfer or command is sent as specified in ``RFC1179''. See the ``Opening Output Device'' section for additional details. 55..1100.. BBoouunnccee qquueeuueess Options used: +o lpd_bounce=_l_p_d _d_o_e_s _f_i_l_t_e_r_i_n_g _a_n_d _t_h_e_n _f_o_r_w_a_r_d_s +o bq=_d_e_s_t_i_n_a_t_i_o_n _f_o_r _p_r_o_c_e_s_s_e_d _j_o_b +o bq_format=_f_o_r_m_a_t _o_f _p_r_o_c_e_s_s_e_d _j_o_b Normally, when using a remote queue, the print job is transmitted to the server computer without any modifications. There are circumstances when modifications must be made to a job before forwarding, such as the desire to convert a job to the format acceptable by the remote printer or to add banner pages. LPRng supports this capability by specifing that a print queue is actually a _b_o_u_n_c_e _q_u_e_u_e rather than a simple forwarding queue. The term _b_o_u_n_c_e _q_u_e_u_e came from the notion that jobs will _b_o_u_n_c_e through this print queue, getting processed by the specified filters, and the filter output will then be forwarded. LPRng will perform all of the usually job processing steps, such as banner generation, filtering files, etc, saving the output text in a file. This file is then sent to the destination print queue for further processing. Again, you will modify the client printcap entry. In the next example, bouncehost is the name of the host which will do the processing, and remote is the target host with the printer. # Simple example of a bounce queue bounce:lp=bounce@bouncehost bounce:server :bq=lp@remote :sd=/usr/spool/lpd/bounce :if=/usr/local/bin/lpf :vf=/usr/local/bin/lpf :bq_format=l # uncomment ab if you want banner #ab # Even Simpler example of a bounce queue bounce:lp=bounce@bouncehost bounce:server :lpd_bounce :lp=lp@remote :sd=/usr/spool/lpd/bounce :if=/usr/local/bin/lpf :vf=/usr/local/bin/lpf :bq_format=l # uncomment ab if you want banner #ab Some comments: 1. For clients, lp=bounce@bouncehost entry specifies the queue and hostname where the filtering will be done. This information is used by the lpr program to determine where to send the print job. 2. If the lpd_bounce option is used, the filtered output is then transmitted to the queue and hostname specified by the lp option (or the rm and rp options). This is the preferred method. 3. If the bq option is used, the filtered output is then transmitted to the queue and hostname specified by the bq option. It is recommended that this option not be used. 4. We need a spool directory (sd) on the lpd server host to hold the files and temporary output while they are processed. 5. Next, we need to indicate the filters to be used for different printer formats. _O_o_p_s_, _I _s_t_i_l_l _d_i_d_n_'_t _t_e_l_l _y_o_u _a_n_y_t_h_i_n_g _a_b_o_u_t _f_i_l_t_e_r_s_. _J_u_s_t _a _m_o_m_e_n_t_, _i_t_'_s _o_n _i_t_s _w_a_y_. _S_e_e _s_e_c_t_i_o_n _`_`_F_i_l_t_e_r_s_'_'_. 6. The print job will be processed by the filters, banner pages generated, etc., and the entire output will be sent to the destination as a single file. 7. The bq_format specifies the format for the output file. If not specified, it default to l (literal or binary). 8. You do not need to use a bounce queue and all of the associated filters to simply change the format names. The simple translate_format=vlxf option will rename format x files to f and there is no filter for format x. See ``translate_format'' for more details. 9. The ab (always print a banner) flag will force a banner to be added to the job. The banner generation is done as discussed in ``Banner Printing''. In this example, anything sent to the printer called bounce (on this host) will be filtered on the client host. After that, it will be transmitted to the queue lp on the server called rreemmoottee. 55..1111.. LLPPRR FFiilltteerriinngg Options used: +o lpr_bounce _l_p_r _d_o_e_s _f_i_l_t_e_r_i_n_g Some users would like to have all of the advantages of having the filtering and processing capabilities of a lpd daemon without needing to deal with actually running a lpd daemon on their system. By having the lpr program process the job by passing it through the various filters and then send the output of the filters as the print job you can get the desired effect. # Simple example of an lpr_bounce entry bounce :lpr_bounce :lp=lp@remote :if=/usr/local/bin/lpf The lpr_bounce flag, if present in the printcap entry, will force lpr to process the job using the specified filters and send the outputs of the filters to the remote printer for further processing. In order to do filtering, it may need to create some temporary files and run some programs. By default, the temporary files are created in the /tmp directory and the programs are run as user. Since no spool directory is used, the sd information is not needed. 55..1122.. DDyynnaammiicc RRoouuttiinngg Options used: +o destinations=_d_e_s_t_i_n_a_t_i_o_n_s _f_o_r _j_o_b_s +o router=_r_o_u_t_e_r _p_r_o_g_r_a_m The LPD bounce queue functionality has been extended to allow a job to not only be passed through filters before sending to a remote destination, but also to reroute the job to one or more destinations in a dynamic manner. This is accomplished by having a router filter return a set of destinations. Here is a sample printcap to accomplish this: t2|Test Printer 2:sd=/var/spool/LPD/t2 :lf=log :lp=t2@printserver :bq=t1@localhost :destinations=t1@localhost,t2@localhost :router=/usr/local/LPD/router The lp entry is used to force all jobs to be sent to the bounce queue on host 'printserver'. Once they arrive, the 'router' filter is invoked with the standard filter options which include the user, host, and other information obtained from the control file. STDIN is connected to a temporary copy of the control file, and the CONTROL environment variable is set to the value of the actual control file itself. The routing filter exit status is used as follows: +o 0 (JSUCC) - normal processing +o 37 (JHOLD) - job is held +o any other value - job is deleted from queue The router filter returns one or more routing entries with the following format. Note that entry order is not important, but each entry must end with the 'end' tag. dest (destination queue) copies (number of copies to be made) priority (priority letter) X(controlfile modifications) end Example of router output: dest t1@localhost copies 2 CA priority B end dest t2@localhost CZ priority Z end The above routing information will have copies of the job sent to the t1 and t2 spool queue servers. If no valid routing information is returned by the router filter the job will be sent to the default bounce queue destination. LPQ will display job information in a slightly different format for multiple destination jobs. For example: Printer: t2@astart2 'Test Printer 2' (routed/bounce queue to 't1@astart2.astart.com') Queue: 1 printable jobs in queue Rank Owner/ID Class Job Files Size Time active papowell@astart2+707 A 707 /tmp/hi 3 10:04:49 - actv papowell@astart2+707.1 A 707 ->t1@localhost 3 10:04:49 - papowell@astart2+707.2 A 707 ->t2@localhost 3 10:04:49 The routing information is displayed below the main job information. Each destination will have its transfer status displayed as it is transferred. By convention, the job identifier of the routed jobs will have a suffix of the form .N added; copies will have CN added as well. For example, papowell@astart2+707.1C2 will be the job sent to the first destination, copy two. Routed jobs can be held, removed, etc., just as normal jobs. In addition, the individual destination jobs can be manipulated as well. The LPC functionality has been extended to recognize destination jobids as well as the main job id for control and/or selection operations. The optional destinations entry specifies the possible set of destinations that the job can be sent to, and is for informational purposes only. In order for LPQ/LPRM to find the job once it has passed through LPD, LPQ/LPRM uses the list of printers in the destinations, and loop over all the names in the list looking for the "job" that you are interested in. If there is no destinations information, the bq information will be usued. One of the more interesting use of the router filter is to actually modify the control file before it is put into the spool queue. The routing filter has STDIN attached to the control file READ/WRITE, allowing the following interesting bit of Perl code to be used: # you need to get PERL to do a 'dup' call on FD 0 open(CF, '+<0'); # read the control file @cf_lines = ; # TRUNCATE the control file truncate(CF,0); # mess about with the control file foreach $line (@cf_lines) { # or whatever you want print CF $line; } This will read the control file, truncate it, and then write it out again. 55..1133.. SSuuppppoorrtt ffoorr NNeettwwoorrkk PPrriinntt SSeerrvveerrss This section was supplied by Horst Fickenscher and updated by Patrick Powell . A ``network print server'' is usually a box (external model) or card in a printer (internal model) which has a network connection to a TCP network and software to implement a LPD print server. If it is an external model, The parallel or serial port of the printer is connected to the box, and the print server may support multiple printers. If it is an internal model, the server is usually nothing more than a Network Interface Controller and a ROM containing software that the microprocessor in the printer uses. The print server may support multiple printing protocols, such as ``RFC1179'' (TCP/IP printing using the LPD print protocol), Novell Printer Protocols, SMB print protocols, and Appletalk protocols. One of the observed problems with Network Print servers is that while they can usually support one protocol and one user at a time quite well, when you try to use multiple protocols and/or multiple users try to transfer print jobs to the printer, the printer may behave in a very odd manner. Usually this results in a printer failing to finish a job currently being printed, and unable to accept new jobs. Several of the newer models of print servers have Simple Network Management Protocol (SNMP) agents built into them, and can provide detailed information about their internal functions. By using a SNMP manager such as SunNetmanage or HP-Openview, you can monitor your network printers activities. Although it's possible to connect to network printers as if they were remote printers, Patrick Powell advises differently: I recommend that you use only a single protocol to send jobs to the printer. If you can, I also recommend that you use a print spooler and have only a single host system send a job to the printer. My best advice on connecting to network printers is not to use the the built-in LPD server, but to use the direct TCP/IP connection to the print engine. Usually this is done to particular TCP/IP port on the printer. For the HP JetDirect and other HP products, this is usually 9100. Once you have the direct connection, you can now use various filters to preprocess the print job, insert PJL and PCL commands, or convert text to PostScript or PCL for better print quality. Here is a sample printcap for an HP LaserJet 4 or above, attached via an HP JetDirect print server. It uses the ifhp filter: # printcap file for pr4 # PostScript via JetDirect card, IP address pr4, port 9100. # Note: some PC's LPR packages use the v format for their jobs # pr4|network :rw:sh:lp=pr4%9100:sd=/usr/spool/lpd/pr4 :af=acct: :lf=log: :ps=status # only allow the following formats :fx=flpv #filters :if=/usr/local/lib/ifhp :of=/usr/local/lib/ofhp :vf=/usr/local/lib/ifhp -c The lp=pr4%9100 means that LPRng is to make a TCP/IP connection to host pr4 on its port 9100. The ifhp filter referenced in if, of, and vf, send PJL (and PCL) commands along with the print files to the printer. The ifhp filter is available from the LPRng distribution sites. Filters are discussed in section ``Filters''. According to Richard S. Shuford , some DEC printers (e.g., the DEClaser 3500) use TCP port 10001. 55..1144.. PPrriinntteerr llooaadd bbaallaanncciinngg In a large site, you could have several equivalent printers, which will be used by many people. The reason for this is, of course, to increase the printer output by enabling several jobs to be printed at once. LPRng supplies mechanisms to define a `virtual' printer for such a set of real printers. If properly set up, print jobs will be distributed evenly over all printers. I'll give two examples for this situation. 55..1144..11.. MMuullttii--sseerrvveerr pprriinntt qquueeuuee Options used: +o ss=_q_u_e_u_e _s_e_r_v_e_d _b_y _p_r_i_n_t_e_r +o sv=_p_r_i_n_t_e_r_s _w_h_e_r_e _j_o_b_s _a_r_e _s_e_n_t _(_s_e_r_v_e_r_s_) A multi-server print queue is one that feeds jobs to other queues. The main queue sv=q1,q2,... printcap entry specifies the names of the printers that will be sent jobs. These printers must have their spool queues on this LPD server. Servers that are fed jobs have a ss=_m_a_i_n_q_u_e_u_e printcap entry. This informs the lpd server that the queue operates under the control of the _m_a_i_n_q_u_e_u_e print queue, and is fed jobs from it. During normal operation, when the lpd server has a job to print in the _m_a_i_n_q_u_e_u_e, it will check to see if there is an idle _s_e_r_v_i_c_e queue. If there is, it will transfer the job to the service queue spooling directory and start the service queue printing activities. Users can send jobs directly to the individual printers serving a queue. The next example (and the comments underneath) was supplied by John Perkins (slightly edited). Here's how I've set up a bounce queue that feeds 6 LaserWriters: laser|pi|Room 1359 LaserWriters :lp=laser@server.com laser|pi|Room 1359 LaserWriters :server :lf=/usr/adm/laser-log :sv=laser1,laser2,laser3,laser4,laser5,laser6 :sd=/usr/spool/laser @commonlaser :sd=/usr/spool/%P :rw:mx#0:sh :lf=/usr/adm/laser1-log :if=/s/lprng/lib/filters/cappsif :of=/s/lprng/depend/cap/bin/papof :ss=laser :fx=fdginpt laser1|pi1|Room 1359 LaserWriter #1 :lp=laser1@server.com laser1|pi1|Room 1359 LaserWriter #1 :server :lp=/dev/laser1 :tc=@commonlaser laser2|pi2|Room 1359 LaserWriter #1 :lp=laser2@server.com laser2|pi2|Room 1359 LaserWriter #2 :server :lp=/dev/laser2 :tc=@commonlaser and so on for the other 4 laser_N queues. This will forward a job from laser to laser_N, once one of those queues is available. It will hold jobs in the ``laser'' queue until one of the other queues is empty. Even though the queues are not meant for direct use, people can print directly to individual queues. This allows a specific load sharing printer to be used. If you wanted to _h_i_d_e the load sharing printers, i.e. - not allow direct spooling to them, then you would simply remove the non-server entries from the printcap. 55..1144..22.. CChheecckkiinngg BBuussyy SSttaattuuss ooff SSeerrvveerr QQuueeuueess Options used: +o check_idle=_c_h_e_c_k _f_o_r _i_d_l_e _p_r_i_n_t_e_r _p_r_o_g_r_a_m The previous section outlined how LPRng uses the sv and ss flags to indicate that the server spool queue has multiple destination queues. However, there is a problem when the actual printer being served by the destination queue is a remote device, and can be busy or offline. The check_idle option specifies a program that is invoked by the lpd server to determine if the spool queue device is available. The program is invoked with the standard filter options, STDIN and STDOUT connected to /dev/null, and STDERR to the error log. The program should make a connection to the remote device or system and should determine that the remote device is available for use, and then exit with the following status. Key Value Meaning JSUCC 0 Successful - printer is idle JABORT non-zero Printer is not accepting jobs If the printer is accepting jobs but is temporarily busy, the program should poll the printer until it becomes free, only exiting when it is available for use. If the printer is not accepting jobs, the program should exit with a non-zero exit code. The following is a sample printcap entry, showing how the check_idle facility can be used. pr: :lp=laserjet%9100 :check_idle=/usr/local/filters/remote_check lp@laserjet :if=/usr/local/filters/ifhp The following perl program shows how to generate a query to the remote printer by simulating an lpq query and checking for returned status. #!/usr/local/bin/perl # Usage: # remote_check printer@host[%port] [-options] # -Tflag[,flags]* # flag # debug - turns debugging on # long - use long status format # # query the remote printer whose name is passed on the command line # # Note that -Txxx options are passed AFTER the printer use English; use IO::Socket; my $JSUCC = 0; my $JABORT = 33; my $JNOSPOOL = 38; my $JNOPRINT = 39; my $debug = 0; my $optind; # pull out the options my($key,$value,$opt,$long,$opt_c); $printer = $ARGV[0]; for( $i = 1; $i < @ARGV; ++$i ){ $opt = $ARGV[$i]; print STDERR "XX opt= $opt\n" if $debug; if( $opt eq '-c' ){ $opt_c = 1; } elsif( ($key, $value) = ($opt =~ /^-(.)(.*)/) ){ if( $value eq "" ){ $value = $ARGV[++$i]; } ${"opt_$key"} = $value; print STDERR "XX opt_$key = " . ${"opt_$key"} . "\n" if $debug; } else { $optind = $i; last; } print STDERR "XX opt_P = $opt_P\n" if $debug; } $long = 0; # short if( defined($opt_T) ){ print STDERR "XX CHECK_REMOTE opt_T=$opt_T\n" if $debug; if( $opt_T =~ /debug/ ){ $debug = 1; } if( $opt_T =~ /short/ ){ $long = 1; } if( $opt_T =~ /long/ ){ $long = 0; } } print STDERR "XX CHECK_REMOTE " . join(" ",@ARGV) . "\n" if $debug; if( !defined($printer) or $printer =~ /^-/ ){ print STDERR "$0: no printer value\n"; exit( $JABORT ); } while( checkstatus( $printer, $long ) ){ print STDERR "XX CHECK_REMOTE sleeping\n" if $debug; sleep(10); } exit $JSUCC; sub checkstatus { my ($printer,$long) = @_; my ($remote,$port); my ($count, $socket, $line); if( $long ){ $long = 4; } else { $long = 3; } if( $printer =~ /@/ ){ ($printer,$remote) = $printer =~ m/(.*)@(.*)/; } $remote="localhost" unless $remote; if( $remote =~ /%/ ){ ($remote,$port) = $remote =~ m/(.*)%(.*)/; } $port = 515 unless $port; print STDERR "XX CHECK_REMOTE remote='$remote'," . " port='$port', pr='$printer', op='$long'\n" if $debug; $socket = getconnection( $remote, $port ); $count = -1; # send the command printf $socket "%c%s\n", $long, $printer; while ( defined( $line = <$socket>) && $count < 0 ){ chomp $line; print STDERR "XX CHECKREMOTE '$line'\n" if $debug; if( $line =~ /printing disa/ ){ print STDERR "XX CHECKREMOTE printing disable\n" if $debug; exit $JNOPRINT; } elsif( $line =~ /spooling disa/ ){ print STDERR "XX CHECKREMOTE printing disable\n" if $debug; exit $JNOSPOOL; } elsif( $line =~ /([0-9]*)\s+job.?$/ ){ $count = $1; print STDERR "XX CHECKREMOTE $count jobs\n" if $debug; } } close $socket; if( $count < 0 ){ print STDERR "CHECKREMOTE cannot decode status\n"; exit $JABORT; } return $count; } sub getconnection { my ($remote,$port) = @_; my ($socket); print STDERR "XX CHECK_REMOTE remote='$remote', port=$port\n" if $debug; $socket = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $remote, PeerPort => $port, ); if( !$socket ){ print STDERR "CHECK_REMOTE IO::Socket::INET failed - $!\n"; exit $JABORT; } $socket->autoflush(1); $socket; } The example of the previous section can be modified now so that it uses the check_idle facility. The master queue will send jobs only to the server queue queues which report idle status. laser1|pi1|Room 1359 LaserWriter #1 :server:check_idle=/usr/local/lib/filters/remote_check pr@laser1 :lp=laser1%9100 :tc=@commonlaser laser2|pi2|Room 1359 LaserWriter #2 :server:check_idle=/usr/local/lib/filters/remote_check pr@laser1 :lp=laser2%9100 :tc=@commonlaser 55..1144..33.. UUssiinngg aa rroouutteerr ffiilltteerr A router filter allows you to re-route jobs in a dynamic way. For details, see ``routing''. Lars Anderson supplied this example (slightly edited): This script will attempt to distribute print jobs evenly on 2 printers hpl5a and hpl5b when sending to hpl5bounce. hpl5bounce|for PLP/LPRng software - network based HP Jetdirect card: :lf=log.hpl5 :lpr_bounce :lp=hpl5b@localhost :router=/usr/local/admscripts/bouncer.pl hpl5a|for PLP/LPRng software - network based HP Jetdirect card: :af=acc.hpl5a: :lp=hpl5a%9100:sd=/var/spool/lpd/hpl5a: :lf=log.hpl5a: :tc=@hplcommon hpl5b|for PLP/LPRng software - network based HP Jetdirect card: :af=acc.hpl5b: :lp=hpl5b%9100:sd=/var/spool/lpd/hpl5b: :lf=log.hpl5b: :tc=@hplcommon # Common settings @hplcommon: :rw:sh:ps=status: :fx=flp: :if=/usr/local/lib/filters/ifhp -Tbanner=on :of=/usr/local/lib/filters/ofhp -Tbanner=on The perl script bouncer.pl looks like this: #!/usr/bin/perl # # Script for printjob loadsharing # # 29/5-97 Lars Anderson # # Printqueues to check $printer1="hpl5a\@localhost"; $printer2="hpl5b\@localhost"; # obtain number of jobs in each printqueue $lpq1=`/usr/local/bin/lpq -s -P$printer1`; $lpq2=`/usr/local/bin/lpq -s -P$printer2`; $lpq1=~ (/(\d+) jobs?/); $numjobs1=$1; $lpq2=~ (/(\d+) jobs?/); $numjobs2=$1; if ($numjobs1 == 0) { print "dest $printer1\nCA\nend\n"; exit; } if ($numjobs1 > $numjobs2) { print "dest $printer2\nCA\nend\n"; exit; } print "dest $printer1\nCA\nend\n"; 55..1155.. TThhee MMiissssiinngg DDeettaaiillss Options used: +o printcap_path=_p_r_i_n_t_c_a_p _f_i_l_e _l_o_c_a_t_i_o_n_s +o lpd_printcap_path=_a_d_d_i_t_i_o_n_a_l _s_e_r_v_e_r _p_r_i_n_t_c_a_p _f_i_l_e _l_o_c_a_t_i_o_n_s The LPRng software uses a greatly simplified set of printcap conventions. This section discusses the details of the printcap database. LPRng can use vintage (i.e.- Berkeley LPR) format printcap files; use the checkpc program to make sure they are totally compatible with LPRng (see checkpc man page, README.install, LPRng- HOWTO). The client programs (LPR, LPRM, LPQ, LPC) do not need access to a printcap database, but will use it if available. The -Pprinter@host option or PRINTER environment variable specifies the printer and LPD host; the LPD server does all of the various spool queue activities. The client programs send requests and/or jobs to the LDP server which carries out all activity. If no printcap is available and the host is not specified, a default host value is provided. If a printcap database is desired, then it is obtained as follows. First, the printcap_path and lpd_printcap_path configuration information (see ``lpd.conf(5)'') specifies where client and server programs find printcap information. The client programs use printcap_path; lpd uses both printcap_path and lpd_printcap_path. All files are read and the printcap entries are extracted in order from the files. Later printcap information overrides previous information in the files. The common defaults for the printcap locations are: printcap_path /etc/printcap:/usr/etc/printcap:\ /var/spool/lpd/printcap.HOSTNAME lpd_printcap_path /etc/lpd_printcap:/usr/etc/lpd_printcap The most common method of printcap information distribution is to have a master printcap file shared or distributed to all system. This usually has only the printer name and lpd host specified in the printcap entries, as shown below. ----- /etc/printcap on clients and server ------- #parallel attached DUMB printer pr1|dumb :lp=pr1@taco.astart.com # server information pr2|postscript :lp=pr2@taco.astart.com pr3|laserjet :lp=pr3@taco.astart.com @common|common code for printers :if=/bin/filter :of=/bin/filter @morecommon|show the configuration expansion :sd=/var/spool/lpd/%P realpr:tc=@common:tc=@morecommon A careful study of the above example will discover the following features of the LPRng printcap structure. 1. Lines ending with a \ indicate continuation to the next line. In practice, the \ is replaced with space(s) when line joining is done. 2. Blank lines and lines whose first nonwhitespace character is a # are ignored, except if it follows a continuation line. (Which makes sense.) 3. All leading and trailing whitespace on a line are removed. 4. A printcap entry consists of a name, 0 or more aliases, and data entries. - name starts with an alphabetic character; dummy entries can start _, @ or . - alias starts with a | followed by the alias - fields or data entry starts with : followed by the entry 5. Field or data entry _n_a_m_e - main or cannonical name for printcap entry |_n_a_m_e - alias _n_a_m_e for printcap entry :_k_e_y - set the _k_e_y to ON (1) :_k_e_y@ - set the _k_e_y to OFF (0) :_k_e_y#_n_n_n - set the _k_e_y to _n_n_n, where _n_n_n follows C language conventions :_k_e_y=_s_t_r_i_n_g - set the _k_e_y to the string value to end of line 6. Printcap entries whose cannonical name starts with _, @, or . (period) (eg.- @_n_a_m_e) are treated like dummy entries. They can be referenced with :tc=_e_n_t_r_y:, but will be ignored otherwise. 7. The tc=f1:tc=f2:... acts similar to a file inclusion operator, but substitutes printcap entries. The specified tc entries are logically append to the end of the current printcap entry, and the appended information will override the previous information. Note that you can have multiple :tc: entries. 8. _k_e_y=_v_a_l_u_e_.%_X a selected set of %_X values are expanded when the printcap entry is used by the client or server program. The following values are expanded: P - printcap cannonical or main name H - Fully Qualified Domain Name for host h - short name for host R - Fully Qualified Domain Name for remote host host r - short name for remote host host 9. The oh entry specifies that a particular printcap entry can only be used by a host with a matching host name or IP address. See ``Master Printcap Files'' for details. 10. The server entry specifies that a particular printcap entry can only be used by the lpd server, and is ignored by other programs. See ``Shared Printcap Files'' for details. Printcap information is extracted in order from the printcap files, and later information for printcap entries overrides earlier ones. The %_X substitution is especially useful when most of the information for a set of printers is common or identical. This can be placed in a printcap entry and referenced with the tc operator. As shown in the example, by making the spool directory name depend on the cannonical printcap name, it simplifies management of the printer. 55..1155..11.. SSppooooll ((CCoonnttrrooll)) DDiirreeccttoorryy PPrriinnttccaapp FFiillee You can put a printcap file in a spool queue directory. This file is only consulted by the LPD server when performing operations on a spool queue. It allows you to put information particular to a spool queue in well controlled location. The server tag and oh options have rendered this facility obsolete, and it may be removed in later releases. 55..1155..22.. SSeeppaarraattee PPrriinnttccaapp FFiilleess ffoorr LLPPDD Since only the LPD server uses the /etc/lpd_printcap or /usr/etc/lpd_printcap file, you can place server specific information there. This allows you to have a common printcap file for clients and an additional one for the lpd servers. You may have to modify the lpd.conf file lpd_printcap_path entry to specify the desired file. The server and oh options have rendered this facility obsolete and it may be removed in future releases of LPRng. 55..1155..33.. PPrriinnttccaapp EEnnttrryy aallll The 'all' printcap entry is reserved to provide a list of all printers available for use by the spooling software. This was intended to be used with systems that did not have ways to provide a wildcard search of the printcap database. The 'all' printcap entry has the form: all:all=pr1,pr2,... The LPRng software will use the individual entries of the printer list and request additional printcap information if necessary. 55..1155..44.. MMoorree EExxaammppllee PPrriinnttccaapp EEnnttrriieess The following printcap entries show the formats, and have some additional comments about fields in the printcap file. # # NOTE: # Use the lpf filter (supplied with LPRng) or the of and if filter. # Banners will be printed using the lpbanner # program, supplied with LPRng. You can also create your own banner # program and specify it as the banner printer (printcap :bp: entry.) # Put -$ at the start of a filter or program specification to suppress # additional command line options. (see lpd.conf). # Note: some PC's LPR packages use the v format instead of the l or f format # # This is the VINTAGE form of printcap, with trailing \ to extend information # to next line. Note the -$ to suppress adding options to command line # typical dump printer, no banner, parallel port pr1|dumb- no banner:\ :sh:lp=/dev/lpr1:sd=/usr/spool/lpd/pr1:\ :fx=flpv:\ :af=acct:lf=log:\ :if=/usr/local/bin/lpf:\ :vf=-$ /bin/cat # dumb with banner - note that lprng will use the default banner program # /usr/local/bin/lpbanner to generate full banner # Note: we use the standard LPRng printcap format pr1b|dumb- banner :lp=/dev/lpr1:sd=/usr/spool/lpd/pr1 #<- sh deleted :fx=flpv :af=acct:lf=log :of=/usr/local/bin/lpf :if=/usr/local/bin/lpf :vf=/usr/local/bin/lpf -c # common printer information: # we define a @common entry @filter|printcap filter information :of=/usr/local/bin/lpf :if=/usr/local/bin/lpf :vf=/usr/local/bin/lpf -c # dumb with user banner - bp specifies banner printer # If we wanted the banner at the END of the job, we would use # :hl: (header last) flag. # We can also have headers at start and end, using the # be={banner printer} and bs={banner printer} overrides # Note: -$ suppresses adding command line options pr1b|dumb- user supplied banner :lp=/dev/lpr1:sd=/usr/spool/lpd/pr1 :fx=flpv :af=acct:lf=log :bp=/usr/local/lib/my_banner_printer :tc=@filter #serial attached PostScript printer # Note that fields can have terminating colons (:) # You can put comments into this printcap with this form # Note that the of filter does accounting pr2|postscript - no banner :rw:sh:lp=/dev/ttya:sd=/usr/spool/lpd/pr2 :stty=9600 -raw -parenb cs8 crtscts :af=acct:lf=log:ps=status # only allow the following formats :fx=flpv # filters :tc=@filter #serial attached PostScript printer with psof created banner pr2|postscript - psof will expand short banner # Note: sb is short banner format # psof filter recognizes this and produces a fancy banner # from the input :rw:sb:lp=/dev/ttya:sd=/usr/spool/lpd/pr2 :stty=9600 -echo -crmod -raw -oddp -evenp pass8 cbreak ixon :af=acct:lf=log:ps=status # only allow the following formats :fx=flpv # filters :tc=@filter #serial attached PostScript printer with user created banner pr2|postscript - psof will expand short banner # Note: sb is short banner format # psof filter recognizes this and produces a fancy banner # from the input :rw:sb:lp=/dev/ttya:sd=/usr/spool/lpd/pr2 :stty=9600 -echo -crmod -raw -oddp -evenp pass8 cbreak ixon :af=acct:lf=log:ps=status # only allow the following formats :fx=flpv # filters :tc=@filter # parallel attached Laser Jet # Note that fields do not need terminating colons # pr3|laserjet :rw:sh:lp=/dev/lp:sd=/usr/spool/lpd/pr3 :af=acct:lf=log:ps=status # only allow the following formats :fx=flpv #filters :if=/usr/local/lib/ifhp -Tstatus=off :of=/usr/local/lib/ofhp -Tstatus=off :vf=/usr/local/lib/ifhp -c -Tstatus=off # printcap file for pr4 # PostScript via JetDirect card, IP address pr4, port 9100. # Note: some PC's LPR packages use the v format for their jobs # pr4|network :rw:sh:lp=pr3%9100:sd=/usr/spool/lpd/pr4 :af=acct: :lf=log: :ps=status # only allow the following formats :fx=flpv #filters :if=/usr/local/lib/ifhp :of=/usr/local/lib/ofhp :vf=/usr/local/lib/bin/ifhp -c 55..1155..55.. PPCC--NNFFSS PPrriinntt SSppoooolleerr If you are using PC-NFS to do print spooling you have several security loopholes exposed. You must modify the permissions on the spool directory to allow other users to access it and place jobs into the directory. Printcap and other control information by default is placed in the spool directory, and can be easily modified by malicious users. To reduce this risk, the :cd: (control directory) entry is used to specify a directory to hold sensitive control information. For example #/etc/lpd_printcap # PCNFS Spooler # pr7 :lp=pr7@printserver :bq=pr1@printserver :sd=/usr/spool/pcnfs/pr7 :cd=/usr/spool/lpd/pr7 This printcap entry will implement a simple 'bounce queue', in which jobs are stored temporarily and then transferred to another spool queue, and is the recommended way to support PC-NFS printing. 55..1166.. MMaannaaggeemmeenntt SSttrraatteeggyy ffoorr LLaarrggee SSiitteess One very effective way to organize print spooling is to have a small number of print servers running a lpd daemon, and to have all the other systems send their jobs directly to them. By using the above methods of specifying the printer and server host you eliminate the need for more complex management strategies. However, you still need to inform users of the names and existence of these printers, and how to contact them. One method is to use a common /etc/printcap file which is periodically updated and transfered to all sites. Another method is to distribute the information using the NIS or some other database. LPRng has provided a very flexible method of obtaining and distributing database information: see ``Using Programs To Get Printcap Information'' for details. 55..1177.. UUssiinngg PPrrooggrraammss TToo GGeett PPrriinnttccaapp IInnffoorrmmaattiioonn In the lpd.conf file you can specify: printcap_path=|program This will cause the LPRng software to execute the specified program, which should then provide the printcap information. The program is invoked with the standard filter options, and has the name of the printcap entry provided on STDIN. The filter should supply the print- cap information on stdout and exit with a 0 (success) error code. By convention, the printcap name 'all' requests a printcap entry that lists all printers. This technique has been used to interface to the Sun Microsystem NIS and NIS+ databases with great success. By having the invoked program a simple shell script or front end to the nismatch or ypmatch programs, the complexity of incorporating vendor specific code is avoided. 55..1177..11.. HHooww ttoo uussee NNIISS aanndd LLPPRRnngg This note is based on material sent to the lprng@iona.ie mailing list by Paul Haldane . # From: Paul Haldane # To: lprng@iona.ie # Subject: Re: Problem using plp with NIS # Sender: majordomo-owner@iona.ie # Precedence: bulk # Reply-To: lprng@iona.ie # Status: RO # We generally don't use NIS for printcap files (we've moved to hesiod) but I can show you what we've done in the past. The input to NIS is a normal printcap file: # Classical printcap entry lp23a|lp23|lp|main printhost printer - KB, EUCS front Door:\ :lp=lp23a@printhost:\ :sd=/usr/spool/lpr/lp23a: #lprng printcap entry lplabel|lpl|TEST - Labels printer: :lp=:rm=printhost:rp=lplabel: :sd=/usr/spool/lpr/lplabel: :rg=lpadm:mx#1: To build the NIS printcap.byname map we add the following to the NIS makefile (along the other bits and pieces that the makefile needs to know about a new map). PRINTCAP=$(DIR)/printcap #PRINTCAP=/etc/printcap # warning : [ ] is actually [] in the script printcap.time: $(PRINTCAP) Makefile if [ -f $(PRINTCAP) ]; then \ sed < $(PRINTCAP) \ -e 's/[ ][ ]*$$//' -e '/\\$$/s/\\$$/ /' \ | awk '$$1 ~ /^#/{next;} $$1 ~ /^[:|]/ {printf "%s", $$0; next;} \ {printf "\n%s", $$0 }' \ | sed -e 's/[ ]*:[ ]*:/:/g' -e 's/[ ]*|[ ]*/|/g' \ -e '/^[ ]*$$/d' > .printcap.$$$$; \ cat .printcap.$$$$; \ if [ $$? = 0 -a -s .printcap.$$$$ ]; then \ awk <.printcap.$$$$ '{ FS=":"; OFS="\t"; } { \ n = split($$1, names, "|"); \ for (i=1; i<=n; i++) \ if (length(names[i]) > 0 \ && names[i] !~ /[ \t]/) \ print names[i], $$0; \ }' | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/printcap.byname; \ awk <.printcap.$$$$ '{ FS=":"; OFS="\t"; } { \ n = split($$1, names, "|"); \ if (n && length(names[1]) > 0 && names[1] !~ /[ \t]/) \ print names[1], $$0; \ }' | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/printcap.bykey; \ rm -f .printcap.$$$$; \ touch printcap.time; echo "updated printcap"; \ fi \ fi @if [ ! $(NOPUSH) -a -f $(PRINTCAP) ]; then \ $(YPPUSH) printcap.byname; \ $(YPPUSH) printcap.bykey; \ touch printcap.time; echo "pushed printcap"; \ fi To specify that you want YP database rather than file access, use the following entry in your /etc/lpd.conf file: printcap_path |/usr/local/lib/pcfilter Put the following shell script in /usr/local/lib/pcfilter #!/bin/sh #/usr/local/lib/pcfilter read key ypmatch "$key" printcap.byname 55..1177..22.. HHooww ttoo uussee NNIISS aanndd LLPPRRnngg -- SSvveenn RRuuddoollpphh Date: Wed, 11 Sep 1996 00:11:02 +0200 From: Sven Rudolph To: lprng@iona.ie Subject: Using :oh=server: with NIS When I use a cluster-wide printcap, two entries for each printer will appear, e. g.: ---------- start of /etc/printcap snippet lp1 :lp=lp1@server lp2 :lp=lp2@server lp1 :server:oh=servername :sd=/var/spool/lpd/lp1 :lp=/dev/lp1 :sh:mx#0 ---------- end of /etc/printcap snippet When I create a NIS map out of this, the printer name is used as a key and must be unique. So NIS' makedbm decides to drop all but the last entry for each printer. This makes the printer on the clients unavailable. I solved this by a hack where the second entry is called lp1.server and the NIS client script has to request the right entry. 1. Assumptions Perl is available at the YP server in /usr/bin/perl . A Bourne Shell is available at all clients in /bin/sh The printcap that is to be exported is in /etc/printcap . The printcap is written in the new format. In the examples the printer is called lp1 . 2. Add the following to your YP Makefile (/var/yp/Makefile) on the YP server : ---------- start of /var/yp/Makefile snippet PRINTCAP = /etc/printcap printcap: $(PRINTCAP) @echo "Updating $@..." $(CAT) $(PRINTCAP) | \ /usr/lib/yp/normalize_printcap | $(DBLOAD) -i $(PRINTCAP) \ -o $(YPMAPDIR)/$@ - $@ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi ---------- end of /var/yp/Makefile snippet (These lines are for Debian GNU/Linux, other systems might require other modifications) 3. Install the programs match_printcap and normalize_printcap to /usr/lib/yp. normalize_printcap is only required on the YP server. The normalize_printcap processes only the LPRng printcap format. ---------- start of /usr/lib/yp/normalize_printcap #! /usr/bin/perl $debug = 0; $line = ""; $new = ""; while (<>) { chomp; next if ( /^\s*\#.*/ ); s/^\s*$//; next if ( $_ eq '' ); print "new: " . $_ . "\n" if $debug;; if (/^\s/) { # continuation line $line = $line.$_; print "continued: $line\n" if $debug; next; } else { $line =~ s/\s+\:/:/g; $line =~ s/\:\s+/:/g; $line =~ s/\:\s*\:/:/g; print "line: $line\n" if $debug; push(@lines, $line) if $line; $line = $_; } } $line =~ s/\s+\:/:/g; $line =~ s/\:\s+/:/g; $line =~ s/\:\s*\:/:/g; push(@lines,$line) if $line; @lines = sort(@lines); foreach $line (@lines) { ($printers) = split(/\:/,$line); @printers = split(/\|/,$printers); foreach $printer (@printers) { $num{$printer}++; push(@allprinters,$printer); print "allprinters: @allprinters\n" if $debug; print $printer."_".$num{$printer}."\t$line\n"; } } @pr = keys %num; print "printers @pr\n" if $debug; if ($#allprinters >=0) { print "all_1\tall:all=".join(",",@pr)."\n"; } ---------- end of /usr/lib/yp/normalize_printcap The result of processing the sample printcap file is: lp1_1 lp1:lp=lp1@server lp1_2 lp1:server:oh=servername:sd=/var/spool/lpd/lp1:lp=/dev/lp1:sh:mx#0 lp2_1 lp2:lp=lp2@server all_1 all:all=lp1,lp2 Observe that each of the real printer entries has a key consisting of the printer name with a numerical suffix. This leads to the following method of extracting the printcap information using ypmatch: ---------- start of /usr/lib/yp/match_printcap #!/bin/sh read p n=1 while ypmatch "${p}_${n}" printcap 2>/dev/null; do n=`expr $n + 1` done ---------- end of /usr/lib/yp/match_printcap 4. Now test the YP arrangement: $ cd /var/yp; make # this should create the printcap map $ ypcat printcap # should provide the whole normalized printcap $ echo lp1 |/usr/lib/yp/match_printcap # yields lp1 printcap 5. Add the printcap_path entry to /etc/lpd.conf: printcap_path=|/usr/lib/yp/match_printcap 6. Test the use of the printcap path entry: $ lpq -Plp1 # shows the status of lp1 7. Restart the lpd server and check to see that it accesses the right printcap information. Use the same lpq command, and then try lpc printcap lp1. 55..1188.. TThhee RReeccoorrdd QQuueeuuee NNaammee qqqq aanndd ffoorrccee__qquueeuueennaammee ffllaaggss Options used: +o qq _I_n_s_e_r_t _q_u_e_u_e _n_a_m_e _i_n_t_o _c_o_n_t_r_o_l _f_i_l_e +o use_queuename _(_a_l_i_a_s _f_o_r _q_q_) +o force_queuename= _Q_u_e_u_e_n_a_m_e _t_o _b_e _u_s_e_d The printcap information consists of the printer name and aliases; when a job is spooled to a printer alias, it is actually spooled to the main printer entry. The qq use queuename option or its alias use_queuename tells LPRng to record the queue name that a job was queued to, and make it available to other software for processing. The force_queuename=... entry forces this name to be used. This capability has some interesting possibilities, as shown below. pr1_landscape|pr1_portrait|pr_raw:lp=pr@host:qq If a job is printed using lpr -Ppr1_landscape, then pr1_landscape will be recorded as the spool queue name by the LPRng software. Later, when the job is processed by a filter, the filter will be invoked with a -Qpr1_landscape command line option. The filter can use the name of the queue to enable say, landscape, portrait, or raw orientations. john|tom|frank:lp=pr@host:force_queuename=office This printcap entry forces the queuename to be office; this information could be used by a central routing facility to process the information is a suitable manner. 55..1199.. UUssiinngg tthhee cchheecckk__ffoorr__nnoonnpprriinnttaabbllee FFllaagg Options used: +o check_for_nonprintable _L_P_R _c_h_e_c_k_s _f_o_r _n_o_n_-_p_r_i_n_t_a_b_l_e _f_i_l_e +o ml# _m_i_n_i_m_u_m _n_u_m_b_e_r _o_f _p_r_i_n_t_a_b_l_e _c_h_a_r_a_c_t_e_r_s +o xt _(_a_l_i_a_s _f_o_r _c_h_e_c_k___f_o_r___n_o_n_p_r_i_n_t_a_b_l_e_) Normally, lpr checks an f format file for non-printable characters (i.e., escape characters) at the start of the print file. Disabling this check allows you to print executable files, etc., which can cause extreme abuse of your printer. Disabling can be done on a single printcap basis, or you can do this on a global basis by modifying the configuration information (see ``lpd.conf''). The ml value specifies the number of characters that are to be checked. Clearly, if it is 0, none will be checked. 55..2200.. TThhee ffdd FFoorrwwaarrddiinngg OOffff OOppttiioonn Options used: +o fd _F_o_r_w_a_r_d_i_n_g _o_f_f When the fd option is on (default is OFF), the lpd server will not accept jobs whose host name in the control file is not the same as one of the hostnames for the host which originates the connection. This was a wimpy attempt to prevent job spoofing. 55..2211.. TThhee rrgg RReessttrriicctt UUssee ttoo GGrroouupp MMeemmbbeerrss OOppttiioonn Options used: +o rg=_R_e_s_t_r_i_c_t_e_d _g_r_o_u_p _l_i_s_t The rg value specifies a list of groups. If this value is present use of a printer or operation is restricted to only users in a particular group. This was a wimpy attempt to do restrictions on print facilities. The -Ppr@host option overrides this check, unless the rg value is put in the LPRng defaults. However, it does provide a simple tool to have clients do some form of permissions checking that only the lpd server could normally do. 55..2222.. TThhee ffxx AAlllloowweedd FFoorrmmaattss OOppttiioonn Options used: +o fx=_s_u_p_p_o_r_t_e_d _f_o_r_m_a_t_s _f_o_r _p_r_i_n_t_i_n_g The fx option restricts the formats supported by a spool queue. The lpr program uses these to check if a requested format is supported. By default, all formats are supported. 55..2233.. FFiixxiinngg BBaadd CCoonnttrrooll FFiilleess aanndd MMeettaacchhaarraacctteerrss RFC1179 defines a simple protocol and standard for print jobs to be interchanged between print spooling systems. Unfortunately, there were some major mistakes in not specifying the exact form that text would take when placed in the control file. In addition, there are some simple coding errors that have been made, but due to their wide distribution in major vendors software, need to be accommodated. See ``reverse_lpq_format'' for an example. 55..2233..11.. DDeeffeeccttiivvee RRFFCC11117799 IImmpplleemmeennttaattiioonnss Options used: +o safe_chars=_a_d_d_i_t_i_o_n_a_l _s_a_f_e _c_h_a_r_a_c_t_e_r_s _f_o_r _c_o_n_t_r_o_l _f_i_l_e Most printer (or print server box) manufacturers totally ignore the details of the RFC1179 protocol and simply accept the data files for printing, disregarding the control file uunnttiill tthheeyy nneeeedd ttoo pprriinntt aa bbaannnneerr oorr pprroovviiddee ssttaattuuss iinnffoorrmmaattiioonn. At this point, you suddenly discover that all sorts of little details will cause horrible problems. For example, the use of non-ASCII characters (i.e. - values are 128-255) in the J (job) line of a control file has been known to crash one network interface card in such a manner that a power-up is needed to restart the printer. Also, as an exercise for the reader, here is another little gem. If you send one particular RFC1179 compatible print spooler a control file with a character whose value is 255 (i.e. 0xFF), the job will never get printed, and there is a mysterious diagnostic on the console: unexpected end of input This is due to the fact that the 0xFF eight bit value is getting sign extended to a 16 bit value 0xFFFF, which just turns out to be -1, or the error indication from a read. 55..2233..22.. OOSS//22 For various reasons, some versions of the OS/2 lpd print spooler have decided to make the control file and data file names have different formats. This can cause LPRng to suspect that somebody is trying to clobber other users jobs, and it will normally reject such jobs. In addition, the OS/2 spooler does not follow RFC1179 correctly, and truncates the data and job file protocol exchange. 55..2233..33.. SSeerriioouuss SSeeccuurriittyy LLoooopphhoollee Finally, there is the subtle and nasty problem with some print filters that are not _m_e_t_a_-_c_h_a_r_-_e_s_c_a_p_e proof. For example, suppose that a user decided to spool a job as follows: lpr '-J; rm -rf /*;' /tmp/a This would create a job file with the line: J `rm /etc/passwd; echo Job;` The job would get printed on a printer with the following printcap: pr:sd=/... :if=/usr/local/hack And of course we have /usr/local/hack (yes, this is a BAD example, so we won't start pointing out all the things): #!/bin/sh while [ -n "$1" ] ; do case "$1" in -J ) shift; args="$args -M$1";; esac; shift; done; # reformat the command line eval /usr/local/realfilter $args The observant reader will notice that the above line gets expanded to: eval /usr/local/realfilter -M`rm /etc/passwd; echo Job;` The interesting thing to observe is that the realfilter will probably execute correctly, while the password file will magically vanish. 55..2233..44.. FFiixxiinngg BBaadd JJoobbss In addition to simple implementation RFC1179 implementation errors, many PC based systems send messages or control files with non-ASCII characters or meta characters in them. In order to prevent problems with LPRng ruthlessly purges all characters but upper and lower case letters, spaces, tabs, and -_.@/:()=,+-% from the control file, replacing suspicious characters with '_'. For some installations, the default set of safe characters may be overly restrictive. For example, _v_i_n_t_a_g_e software may generate files with # characters in the J line of the control file. The replacement of this character may cause other things to stop working. The safe_chars option allows the user to specify an additional set of safe characters in the lpd.conf configuration file(s). For example, safe_chars=#" would allow the # and " characters to appear in the control file. In addition, LPRng will ruthlessly regenerate control file entries and data file names so that they are compliant. 55..2233..55.. UUssiinngg tthhee bbkk OOppttiioonn aanndd CCoonnttrrooll FFiillee FFiilltteerrss Options: +o bk _B_e_r_k_e_l_e_y _c_o_m_p_a_t_i_b_l_e _c_o_n_t_r_o_l _f_i_l_e +o control_filter=_C_o_n_t_r_o_l _f_i_l_e _f_i_l_t_e_r One of the more serious problems is when a print spooler (LPR) program does not generate print jobs in a manner compatible with a remote system. While LPRng performs checks for improper implementations of RFC1179, it will try to accept a job, even under the most severe abuse of the protocol. However, other spoolers are not so forgiving. Some spoolers require that the contents of the control file be in eexxaaccttllyy the order that the original 1988 BSD LPR software generated them. While some entries can be missing, all the entries present in the file must be in an explicit order. The bk (Berkeley LPD compatible control file) option causes LPR and LPD to reformat the control file, removing objectionable entries. The control file of a job being sent to a remote printer will have its control file entries restricted to letters in (and the same order) as HPJCLIMWT1234. However, there are some very odd commercial implementations that require _m_o_r_e information than is present. To assist with this, the control_filter option can be used. This specifies a program that will process the control file before it is sent to a remote destination. See ``Filters'' for details on filter operation, and ``Control Filters'' for more information. The control_filter program is run with the standard set of filter options. STDIN is attached (read/write) to the control file and the filter STDOUT will be used as the control file value sent to the remote host. The control_filter can rewrite the control file, modify the names and formats of the data files, or perform other changes. Here is a small snip of PERL code that shows how to rewrite the control file: # you need to get PERL to do a 'dup' call on FD 0 $status = 0; @cf_lines = ; # mess about with the control file foreach $line (@cf_lines) { # or whatever you want print STDOUT $line; } exit $status; The exit code of the control_filter is used to determine whether to proceed in processing. See ``Errorcodes'' for details. Also, see ``Control Filters'' for more information. 55..2244.. MMaaxxiimmuumm CCooppiieess Options used: +o mc#_m_a_x_i_m_u_m _c_o_p_i_e_s The mc value specifies the maximum number of copies of a job that can be printed on a printer using the lpr -Knn or lpr -#nn option. 55..2255.. TThhee mmiinnffrreeee MMiinniimmuumm SSppooooll QQuueeuuee SSppaaccee OOppttiioonn Options used: +o minfree#_a_l_i_a_s _f_o_r _m_i If this value is non-zero, then the lpd server checks to see that there is the specified number of bytes of file space available before transferring a job. 55..2266.. DDeebbuuggggiinngg Options used: +o debugging=_d_e_b_u_g_g_i_n_g _o_p_t_i_o_n_s +o full_time _f_u_l_l _o_r _e_x_t_e_n_d_e_d _t_i_m_e _f_o_r_m_a_t +o ms_time_resolution _m_i_l_l_i_s_e_c_o_n_d _t_i_m_e _r_e_s_o_l_u_t_i_o_n +o syslog_device=_s_y_s_l_o_g _a_l_t_e_r_n_a_t_i_v_e _d_e_v_i_c_e +o use_date _p_u_t _d_a_t_e _i_n_f_o_r_m_a_t_i_o_n _i_n _c_o_n_t_r_o_l _f_i_l_e +o use_info_cache _c_a_c_h_e _p_r_i_n_t_c_a_p _a_n_d _o_t_h_e_r _i_n_f_o_r_m_a_t_i_o_n The LPRng software has a very powerful debugging capability. Since most printing problems occur on remote systems where it is impossible to run debuggers, and since most systems do not do core dumps of SETUID ROOT programs, the LPRng software provides a very verbose set of log file trace messages. First, serious errors or other information are logged using the _s_y_s_l_o_g_(_) facilities. If these are not present on a system, then the messages are logged to the device specified by syslog_device. For client programs, the debugging options are specified on the command line and output is directed to STDERR. For the lpd server, debugging commands can be specified on the command line OR as the db=options printcap value. Output is directed to the log file (lf option value, default log). A typical debug entry has the format 2,network+1,database. This sets the general debugging level to 2, network debugging to 1 and the database debugging level to the default. The following debugging options and levels are supported. +o nnn - general purpose debugging level +o network - network debugging +o database - database debugging +o receive - job or command reception debugging +o print - detailed job printing debugging The full_time flag forces the logging and other information which has timestamps to have a full (year, month, day, etc.) timestamp. The ms_time_resolution flag forces millisecond time resolution in the time stamp. The use_date flag forces a date value to be placed in a control file if there is none. The use_info_cache (default ON) causes lpd to cache printcap and configuration information. This is desirable except when trying to change values in printcap files and test the results. By using use_info_cache@ in the configuration information, you can get immediate responses. Also, see ``lpc reread'' for another method. 55..2277.. LLPPDD SSppeecciiffiicc Options used: +o ipv6 _u_s_e _I_P_V_6 _N_e_t_w_o_r_k _f_a_c_i_l_i_t_i_e_s +o lockfile=_l_p_d _s_e_r_v_e_r _l_o_c_k _f_i_l_e +o report_server_as=_s_e_r_v_e_r _n_a_m_e _f_o_r _s_t_a_t_u_s _r_e_p_o_r_t_s +o spool_dir_perms#_s_p_o_o_l _d_i_r_e_c_t_o_r_y _p_e_r_m_i_s_s_i_o_n_s +o spool_file_perms#_s_p_o_o_l _f_i_l_e _p_e_r_m_i_s_s_i_o_n_s +o spread_jobs#_j_o_b _n_u_m_b_e_r _s_p_r_e_a_d These options are usually LPD specific. For example, the ipv6 specifies that the IPV6 protocol, rather than IPV4 will be used. In future versions, this may not be necessary. The lockfile specifies the location of the lock file used by the lpd server. The spool_dir_perms and spool_file_perms (default 0700 and 0600 respectively) values are the (numeric) permissions for the spool directory and spool files. The spread_jobs option is obsolete. The spread_jobs option was a desperation fix to handle difficulties with the arrival of a large number of jobs with the same or close job number. The LPD server would fork children, each of whom tried to lock the job files. The spread value randomly chose a new number in the range about the original job number. However, it is still preserved for legacy systems which still have problems with file locking. The report_server_as option allows an administrator to masquerade a server with another name. This could be useful if various load sharing activities are being carried out, or if there are problems reconfiguring DNS to cause the correct server name to be reported. 55..2288.. LLeeggaaccyy CCoommppaattiibbiilliittyy The following arguments have been provided for compatibility with legacy systems. 55..2288..11.. TThhee aallllooww__dduupplliiccaattee__aarrggss OOppttiioonn Options used: +o allow_duplicate_args _a_l_l_o_w _l_p_r _t_o _h_a_v_e _d_u_p_l_i_c_a_t_e _a_r_g_u_m_e_n_t_s Some users would like duplicate LPR and LPRM command line arguments to override earlier ones, i.e. - lpr -a x -a y should be equivalent to lpr -a y The allow_duplicate_args option allows the various client programs to have duplicate arguments. The last specified argument on the command line will override previous values. 55..2288..22.. TThhee ccllaassss__iinn__ssttaattuuss OOppttiioonnss Options used: +o class_in_status _s_h_o_w _c_l_a_s_s _n_a_m_e _i_n _s_t_a_t_u_s Setting the class_in_status option causes the class name rather than priority to be displayed in the status information. 55..2288..33.. TThhee rreevveerrssee__llppqq__ffoorrmmaatt OOppttiioonn Options used: +o reverse_lpq_format= _r_e_v_e_r_s_e _L_P_Q _s_t_a_t_u_s _f_o_r_m_a_t _f_o_r _s_p_e_c_i_f_i_e_d _r_e_m_o_t_e _s_y_s_t_e_m_s Various Solaris and other System V implementations support an RFC1179 interface to remote printers. Unfortunately, there is a problem in that when they send a status request, the status format is reversed. That is, when LONG status format is wanted, they send SHORT, and vice versa. The reverse_lpq_format= specifies a list of printers or IP addresses for which the lpd server will return LONG status when SHORT is requested, and vice versa. For example: reverse_lpq_format=*.eng.com,130.192.0.0/16 will cause hosts whose Fully Qualified Domain Name (FQDN) ends in eng.com or from subnet 130.192.0.0 to have reversed status returned. 55..2288..44.. TThhee rreettuurrnn__sshhoorrtt__ssttaattuuss aanndd sshhoorrtt__ssttaattuuss__lleennggtthh OOppttiioonnss Options used: +o return_short_status= _r_e_t_u_r_n _s_h_o_r_t _L_P_Q _s_t_a_t_u_s _f_o_r _s_p_e_c_i_f_i_e_d _r_e_m_o_t_e _s_y_s_t_e_m_s +o short_status_length# _s_h_o_r_t _L_P_Q _s_t_a_t_u_s _l_e_n_g_t_h _i_n _l_i_n_e_s In order to be compatible with non-LPRng client programs, some administrators would like lpd to return a short or brief status to normal status queries. The return_short_status= specifies a list of printers or IP addresses for which the lpd server will return an abbreviated status when LONG status is requested. For example: return_short_status=*.eng.com,130.192.0.0/16 short_status_length#3 will cause hosts whose Fully Qualified Domain Name (FQDN) ends in eng.com or from subnet 130.192.0.0 to get only 3 lines of detailed status returned. 55..2288..55.. TThhee ffoorrccee__llppqq__ssttaattuuss OOppttiioonnss Options used: +o force_lpq_status= _f_o_r_c_e _L_P_Q _s_t_a_t_u_s _f_o_r_m_a_t _f_o_r _s_p_e_c_i_f_i_e_d _r_e_m_o_t_e _s_y_s_t_e_m_s In order to be compatible with non-LPRng client programs which are totally unpredictable, this allows the administrator to specify the format for LPQ status when requests arrrive. The force_lpq_status= specifies a list of formats and printers or IP addresses for which the lpd server will return status in the sepcified format. The entry has the format KEY=list;KEY=list... where KEY is s for short and l for long format, and list is a list of hosts or IP addresses. For example: force_lpq_status=s=pc*.eng.com,130.192.12.0/24,l=sun*.eng.com will cause hosts whose Fully Qualified Domain Name (FQDN) matches pc*eng.com or from subnet 130.192.12.0 to get short status returned and hosts which match sun*.eng.com get long status. 55..2288..66.. TThhee iiggnnoorree__rreeqquueesstteedd__uusseerr__pprriioorriittyy aanndd ffoorrccee__ffqqddnn__hhoosstt OOppttiioonnss Options used: +o ignore_requested_user_priority_p_r_e_v_e_n_t _u_s_e_r_s _f_r_o_m _q_u_e_u_e _j_u_m_p_i_n_g +o force_fqdn_hostname_f_o_r_c_e _F_Q_D_N _h_o_s_t_n_a_m_e _i_n _c_o_n_t_r_o_l _f_i_l_e Some students... um... users... will request a high priority for their job in order to jump the queue of waiting jobs. This option will cause the lpd server to ignore the requested user priority. However, the topq operation will still be effective. Similarly, some print spoolers do not put a FQDN host name in their control file. The force_fqdn_hostname flag will cause lpd to put a FQDN host name in. 55..2288..77.. TThhee llpprr__bbssdd OOppttiioonnss This will force the lpr -m (send mail to user) option not to take an arguement, as in the BSD lpr. The value of the $USER environment variable will be used as the return address. 55..2299.. CCoommppaattiibbiilliittyy wwiitthh BBSSDD pprriinnttccaapp If you previously had a BSD-style printer spooler, you might be lucky: your printcap will be directly usable by LPRng in many cases, i.e. - LPRng is almost totally backwards compatible with the old BSD printcaps. However, a lot of people have found out the hard way that LPRng is not completely compatible with BSD LPR. For example, the fc/fs/xc/xs flag fields were used to specify serial line options and are no longer supported. The flag fields and their meanings are version and OS dependent and were not portable. The stty value is a subset of ssttttyy((11)) options, and should be able to support whatever configuration you require. See ``Converting BSD fc,fs,xc,xs To LPRng stty'' for details. There are other items, such as the fact that the keywords used by LPRng can be variable length, not just two letters, and other commenting and formatting conventions which are not supported by the older BSD servers. 66.. FFiilltteerrss This section gives an overview of how LPRng uses filter programs, and gives a detailed discussion of how the printcap options and filters interact. 66..11.. WWhhaatt aarree ffiilltteerrss?? Print filters are one of the most powerful tools in BSD-style printer systems. In general UNIX terms, a _f_i_l_t_e_r is a program that takes its input file(s), does something with it, and sends the result to its standard output. Most UNIX utilities are designed as filters. (But since you are a system manager, you should already know that :)) In the context of a BSD-style print spooler (and also LPRng), the term _f_i_l_t_e_r refers to a program that does processing on a file that is submitted to the printer. As such, it is a specific example of the general class of programs called `filters'. Usually the filter is executed with STDIN reading from the file to be printed or program generating the output and STDOUT to the printer device. STDERR (file handle 2) is redirected to a log file, and file handle 3 to an accounting file. A filter can be as simple as a LF to CR/LF translator (the example used before), or it can incorporate a complete accounting system, automatic file type translations, or even redirect the job to another printing system. As part of the LPRng project, the following filters are supported. See the associated documentation for details. +o Distributed in the LPRng source distribution ``lpf'' a very simple CR/LF or passthrough filter. +o Distributed in the FILTERS_LPRng distribution: ``ifhp'' HP PCL and PJL printer filters +o The supported filters and other facilities are available from ftp://ftp.astart.com/pub/LPRng 66..22.. WWhhaatt aarree pprriinntt ffoorrmmaattss?? Options used: +o if, cf, df, gf, nf, of, rf, tf, vf, _Xf, _F_i_l_t_e_r _p_r_o_g_r_a_m_s LPRng has inherited a set of so-called `pprriinntt ffoorrmmaattss' from its BSD ancestor. The format was originally used to specify the type of file that was being printed. The lpd daemon would use the print format to select the required filter for processing the file. TThhee ddeeffaauulltt ffoorrmmaatt iiss f. The user can specify the format (i.e., the file type) by giving the appropriate option to lpr: +o -b or -l: Binary (literal) file. No processing should be done. The l format is recorded as the file format. +o -c: cifplot(1) output. +o -d: TeX DVI file. +o -g: Output from the plot(3X) routines. +o -n or -t: (di)troff output. +o -p: Text file that should be pre-processed by the pr command, and then by the standard text filter. +o -v: Benson Varian raster image. Alternatively, one can also use -Fx, where x is the format specifier. (E.g., -Fc instead of -c.) This last form also allows you to use other (non-standard) format specifiers. The filter for format X is the value for the Xf printcap option, with some minor exceptions. The following Xf options have a pre-defined meaning. +o if The f format filter, i.e. - for the default f format. All print jobs are passed through this one, unless another format is selected. +o cf Cifplot data filter (for -c format). +o df Filter for DVI files (-d). +o gf Graph data filter (-g). +o nf Ditroff data filter (-n). +o of This filter is used for processing the (optional) banner at the start and/or end of the print job, and also for the interjob separators. See ``of'' filter for details. +o rf Filter for Fortran style files (-r). +o tf Troff filter (-t). +o vf (Versatek) raster image filter (-v). 66..33.. OOFF FFiilltteerr The of filter is used to process banners and job separators. The of filter is responsible for performing appropriate processing of this information and sending to the printer for action. While the various file filters are invoked on a once per print file basis, the of filter is invoked on a once per print job basis. This filter is the first one to be started, and should perform whatever specialized device initialization is needed. It should also do whatever accounting procedure is desired for start of job accounting. The of filter will be given any banner printing or job separation information for a job. As part of its operation, it can detect a specific string, corresponding to a banner print request, and generate a banner. (See the ``Job Processing Steps and Printcap Options'' for details.) During operation, the lpd server will send the special ssttoopp sequence of \031\001 to the of filter. The filter must then suspend itself using a kill -STOP operation. The lpd server will detect that the of filter has suspended itself and then will perform other printing operations. After the other printing operations have been completed, the of will then be sent a kill -CONT signal. This sequence will continue until all information has been printed, and then the of filter's STDIN will be closed. The filter will then perform whatever cleanup operations are needed, update accounting or other information, and exit. 66..33..11.. TThhee ffiilltteerr__ppoollll OOppttiioonn Options used: +o filter_poll=_i_n_t_e_r_v_a_l _t_o _c_h_e_c_k _f_o_r _o_f _o_u_t_p_u_t While the of filter operation is very simple in concept, there are some minor implementation and performance problems with it. The lpd server reads and reports any error messages generated by the of filter on FD 2 (stderr). The of filter may write these error messages before it exits or suspends itself. If there is insufficient buffering in the operating system pipe buffer, then the of filter may block until the information is read by the lpd server. If the lpd server is waiting for the filter to exit, then we get a deadlock situation. This deadlock is resolved by having the lpd server block for filter_poll (default 30) seconds, and then check to see if there is any input to be read. This option will effect performance only when the of filter produces a large amount of debugging or trace messages, and when there is insufficient system pipe buffers to hold them all. 66..44.. TThhee llpprr --pp ffoorrmmaatt aanndd pprr ooppttiioonn Options used: +o pr=_p_r _p_r_o_g_r_a_m _f_o_r _p _f_o_r_m_a_t The -p format is implemented by sending the file through the program specified by the pr printcap utility (default is /bin/pr), and passing the result to the normal :if filter. 66..55.. TThhee llpprr --ll ffoorrmmaatt aanndd bbiinnaarryy ffoorrmmaatt The binary (or literal) format is indicated by format type -l. The if filter is used to process the file, and is invoked with the -c (cancel processing?) flag. 66..66.. JJoobb PPrroocceessssiinngg aanndd PPrriinnttccaapp OOppttiioonnss Much of the flexibility of the LPRng software is obtained from the ability to control the details of each step of job processing. The following section details each step in the processing of a job, and explains the printcap options used to control each operation. Assume the pr printcap entry has the form: pr :lp=/dev/lp OR :lp=rp@rm :sd=/var/spool/lpd/pr :lf=log :of=/usr/local/bin/lpf :if=/usr/local/bin/lpf Assume that we have used the following command to print a set of files. lpr -Ppr file1 file2 This will create a control file in the /var/spool/lpd/pr directory with the following contents (this is an example - in practice there may be minor differences between the example and an actual control file): Hastart4.astart.com J/tmp/file1 /tmp/file2 CA Lpapowell Ppapowell fdfA002230astart4.astart.com N/tmp/file1 UdfA002230astart4.astart.com fdfB002230astart4.astart.com N/tmp/file2 UdfB002230astart4.astart.com 66..66..11.. OOppeenniinngg tthhee OOuuttppuutt DDeevviiccee Options used: +o achk _A_c_c_o_u_n_t_i_n_g _c_h_e_c_k _a_t _s_t_a_r_t +o af=_A_c_c_o_u_n_t_i_n_g _F_i_l_e +o ar _R_e_m_o_t_e _p_r_i_n_t_e_r _a_c_c_o_u_n_t_i_n_g _e_n_a_b_l_e_d +o as=_A_c_c_o_u_n_t_i_n_g _a_t _s_t_a_r_t +o connect_grace# _T_i_m_e _b_e_t_w_e_e_n _j_o_b_s +o connect_interval# _C_o_n_n_e_c_t_i_o_n _i_n_t_e_r_v_a_l +o connect_timeout# _C_o_n_n_e_c_t_i_o_n _t_i_m_e_o_u_t +o control_filter=_C_o_n_t_r_o_l _f_i_l_e _f_i_l_t_e_r +o ff _f_o_r_m _f_e_e_d +o fo _f_o_r_m _f_e_e_d _o_n _o_p_e_n +o la _L_o_c_a_l _p_r_i_n_t_e_r _a_c_c_o_u_n_t_i_n_g _e_n_a_b_l_e_d +o ld=_l_e_a_d_e_r _o_n _o_p_e_n _(_i_n_i_t_i_a_l_i_z_a_t_i_o_n _s_t_r_i_n_g_) +o lk _L_o_c_k _I_O _d_e_v_i_c_e +o lp=_I_O _d_e_v_i_c_e _p_a_t_h_n_a_m_e +o nb _N_o_n_b_l_o_c_k_i_n_g _d_e_v_i_c_e _o_p_e_n +o network_connect_grace# _T_i_m_e _b_e_t_w_e_e_n _j_o_b_s +o of=_o_f _f_i_l_t_e_r +o retry_econnrefused# _R_e_t_r_y _i_f _o_p_e_n _f_a_i_l_e_d +o retry_nolink# _R_e_t_r_y _i_f _o_p_e_n _f_a_i_l_e_d +o rm _t_h_e _r_e_m_o_t_e _m_a_c_h_i_n_e _t_o _s_e_n_d _t_h_e _j_o_b _t_o +o rp _t_h_e _r_e_m_o_t_e _p_r_i_n_t _q_u_e_u_e _t_o _s_e_n_d _t_h_e _j_o_b _t_o +o rw _d_e_v_i_c_e _o_p_e_n_e_d _R_W _f_l_a_g +o server_tmp_dir=_t_e_m_p_o_r_a_r_y _d_i_r_e_c_t_o_r_y Sequence of Operations: 1. During the server operations, it will try to create temporary files in the print queue spool directory. If this is not desirable, it will create them in the server_tmp_dir directory. 2. If the accounting file specified by af exists, it is opened (af_fd) and the af_fd is passed as file descriptor 3 to all filters. If the af value has the form af=|/program then the program is started and the program STDIN is used as af_fd. If the af value has the form af=host%port, then a TCP/IP connection to the corresponding port on the remote host is made and the port used as af_fd. In the latter two cases, the filter STDIN (file descriptor 0) is actually opened read/write, and is used when information is needed from the accounting filter or remote server. See ``Accounting Printcap Options'' for more information on the LPRng accounting support. 3. If the connect_grace value is non-zero and the server is opening a device or network_connect_grace is non-zero and a network connection is being made, the server will pause the specified time. This is to accommodate devices which need a recovery time between jobs. 4. The lp option is checked to determine the type of IO device. | | | |Format | Meaning | |/pathname | Absolute pathname of IO device | |pr@host | transfer to pr on remote host | |host%port | open a TCP/IP connection to port on host. host can be name or IP address | ||filter | run the filter program; it STDIN will be used as device | 5. The IO device specified by lp is opened write-only or read-write if the rw flag is true, and the resulting file descriptor is io_fd. If the nb flag is set, a non-blocking open will be done as well. If the lk (lock device) flag is true, the device will be locked against use by other LPD servers. 6. If a host%port combination, a TCP/IP connection will be opened to the remote port and the connection will be used as io_fd. 7. If a filter program is specified, the filter program will be run and the STDIN of the filter will be used as the device file descriptor. 8. If a rp@rm combination, or none of the above combinations are true and the rm and rp values are non-zero, then the job will be transferred to a remote printer. The type of operation will be a job transfer, rather than printing operation. 9. If the connect_timeout value is non-zero, a timeout is setup for the device or socket open. If the device or connection open does not succeed within the timeout, then the open operation fails. 10. If a connection is to a network address (i.e. - connect() system call) and the connection attempt fails with an ECONNREFUSED error, if the retry_econnrefused flag is set then the connection attempt is retried, but this time using an alternative port number. See ``RFC1179'' for details. This is repeated until all of the possible originating port numbers are exhausted. 11. If the open or connect operation fails, and the retry_nolink flag is set, then the server will pause for a minimum of connect_grace plus a multiple of connect_interval seconds based on the number of attempts before retrying the open operation. Note that the interval may increase as the number of attempts increases. 12. If printing a job and the of filter is specified, it is created with its STDOUT (fd 1) attached to the io_fd. Its stdin (of_fd) will be used in the steps listed below. If there is no of filter, then the of_fd value will be the io_fd descriptor. 13. If transferring a job and the control_filter option is specified, then the program specified by the control_filter value will be run. It will have its STDIN set to the control file, and its STDOUT output will be used as the new value of the control file to transfer to the remote host. See ``Filter Command Line Flags'' for details of options passed to the control filter, and ``errorcodes'' for the exit codes of the filter. 14. If la (local accounting) is true and we are printing a job or ar (remote accounting) is true and we are transferring a job, the as value is examined. If it is a filter (program) specification, then the program is started with its STDIN attached to /dev/null and STDOUT to the io_fd, STDERR to the error file, and file descriptor 3 to the accounting file descriptor af_fd. The lpd program will wait until it terminates, and examine the error code for action, as for the filters (see ``errorcodes'' below). If it is a string, then it is interpreted, the escape sequences replaced with the appropriate information, and written to the accounting file. 15. If the achk (accounting check) flag is set, a line is read from the accounting filter af_fd file descriptor. This line should be accept, otherwise the job processing terminates with a JFAIL indication. 16. If the operation is a job transfer, the operation proceeds as outlined in ``RFC1179'', and then the ``Normal Termination'' operations are carried out. 17. If the operation is a print operation and the ld (leader on open) value is provided, the string is translated (escapes removed) and written to the of_fd file descriptor. 18. If the fo (form feed on open) flag is true, then the ff (form feed) string is translated (escapes removed) and written to the of_fd file descriptor. 66..66..22.. PPrriinnttiinngg BBaannnneerr AAtt BBeeggiinnnniinngg Options used: +o ab _A_l_w_a_y_s _p_r_i_n_t _b_a_n_n_e_r _(_d_e_f_a_u_l_t _F_A_L_S_E_) +o be=_E_n_d _b_a_n_n_e_r _g_e_n_e_r_a_t_o_r _p_r_o_g_r_a_m +o bl=_S_h_o_r_t _b_a_n_n_e_r _l_i_n_e _f_o_r_m_a_t +o bp=_B_a_n_n_e_r _g_e_n_e_r_a_t_o_r _p_r_o_g_r_a_m +o bs=_S_t_a_r_t _b_a_n_n_e_r _g_e_n_e_r_a_t_o_r +o hl _B_a_n_n_e_r _(_h_e_a_d_e_r_) _L_a_s_t +o of=_B_a_n_n_e_r _a_n_d _F_i_l_e _S_e_p_a_r_a_t_o_r _F_i_l_t_e_r +o sb _S_h_o_r_t _b_a_n_n_e_r _(_d_e_f_a_u_l_t _F_A_L_S_E_) +o sh _S_u_p_p_r_e_s_s _h_e_a_d_e_r _(_b_a_n_n_e_r_s_) _(_d_e_f_a_u_l_t _F_A_L_S_E_) Sequence of Operations: 1. If the sh (suppress header) flag is true, no banner is printed, and the actions in this section are skipped. 2. If the hl flag is true, the banner is printed at the end of the job, and the actions in this section are skipped. 3. If the user does not supply a banner name, (the L line in the control file) and ab (always print a banner) is false (the default), then no banner is printed. If no name is supplied and ab is true, then ANONYMOUS is used. 4. There are two types of banners - short and long. If the sb flag is set, then we send the bl (banner line) contents directly to the of_fd; By default the bl value is: bl=$-'C:$-'n Job: $-'J Date: $-'t (See ``Filter Command Line Flags'' for details.) This will get translated to: papowell:A Job: file1 file2 Date: Thu Nov 27 23:02:04 PST 1997 5. If the sb flag is clear, we will generate a long banner using a program instead. If bs (start banner) program is specified, then it is used to generate a banner, otherwise if the bp (banner) program is specified, then it is used to generate a banner. If no program is available, we skip the banner generation. The banner generator program is started with the normal command line flags (see ``Filter Command Line Flags''), with its STDOUT attached to the of_fd descriptor. The short banner string described in the previous step is written to the STDIN. The banner printer is responsible for generating a banner appropriate to the printing device. 6. The ff (form feed) string will be interpreted and sent to the of_fd. 66..66..33.. PPrriinnttiinngg JJoobb FFiilleess Options used: +o Xf=_F_o_r_m_a_t _F_i_l_t_e_r +o if=_D_e_f_a_u_l_t _F _F_o_r_m_a_t _F_i_l_t_e_r +o pr=_p_r _f_o_r_m_a_t_t_i_n_g _p_r_o_g_r_a_m +o send_job_rw_timeout= _p_r_i_n_t _j_o_b _r_e_a_d_/_w_r_i_t_e _t_i_m_e_o_u_t +o send_query_rw_timeout= _s_t_a_t_u_s _q_u_e_r_y _o_p_e_r_a_t_i_o_n _r_e_a_d_/_w_r_i_t_e _t_i_m_e_o_u_t +o sf _S_u_p_p_r_e_s_s _F_F _P_r_i_n_t _F_i_l_e _S_e_p_a_r_a_t_o_r_s Sequence of Operations: for each job in listed in the control file, the following operations are done in turn. 1. If there is an of filter present, the suspend string \031\001 is written to of_fd and the no further action is taken until the of filter is suspended. 2. The control file line for the job is examined, and the first letter of the data file specification is used as the format. 3. If the format is p, the job is first processed by the program specified by the pr program, and the program output used as the print file. 4. If the format is f, l, or p then the if filter is used, otherwise the keyword Xf is used. Note that certain formats such as p, a, l, may not be used as formats. 5. The filter program is started with an appropriate set of command line options (see ``Filter Command Line Flags''), and with its STDOUT attached to the printing device (io_fd), STDERR to the log file (lf), and file descriptor 3 to the accounting fd af_fd. 6. When doing a read/write operation to a device or remote system, a timeout can be specified. When doing a print or job transfer operation, the send_job_rw_timeout value is used. When doing a status or query operation, the send_query_rw_timeout value is used. If a write or write operation does not complete within the specified timeout seconds, then we have an error condition and job processing or the query operation is terminated with JFAIL status. If the timeout value is 0, then no timeout is done. 7. lpd will then wait for the filter to exit. The exit status can be as follows: Key Value Meaning JSUCC 0 Successful JFAIL 1, 32 Failed - retry later JABORT 2, 33 Abort - terminate queue processing JREMOVE 3, 34 Failed - remove job JHOLD 6, 37 Failed - hold this job Other Abort - terminate queue processing 8. If the filter exit status was JSUCC (0), or no error indicated, then processing will continue otherwise the job termination takes (see ``Abnormal Termination''). 9. If the of filter is present, then it is reactivated with a kill -CONT signal. 10. If the sf (suppress FF print file separators ) is false, then the ff (form feed) string will be interpreted and sent to the of_fd. 66..66..44.. PPrriinnttiinngg BBaannnneerr AAtt EEnndd Options used: +o hl _H_e_a_d_e_r _(_B_a_n_n_e_r_) _L_a_s_t The actions taken in this step are identical to those for the ``Printing Banner At Beginning'', with the exception that the be (end banner program) is used in the procedure rather than the bs (start banner program). 66..66..55.. NNoorrmmaall TTeerrmmiinnaattiioonn Options used: +o fq _F_o_r_m _F_e_e_d _o_n _C_l_o_s_e +o la _L_o_c_a_l _P_r_i_n_t_e_r _A_c_c_o_u_n_t_i_n_g +o tr=_T_r_a_i_l_e_r _o_n _C_l_o_s_e +o ae=_A_c_c_o_u_n_t_i_n_g _a_t _e_n_d +o save_when_done _S_a_v_e _w_h_e_n _d_o_n_e Sequence of Operations: 1. If we are printing and the fq flag is set and the sf (suppress interfile FF) flag is set, then the ff (form feed) string will be interpreted and sent to the of_fd. 2. If we are printing, the tr (trailer) string will be interpreted and sent to the of_fd. 3. If printing and the la (local printer accounting) flag is set or transferring a job and the ar (remote accounting) flag is set, the ae is examined and accounting is done as described for the ``as'' field. 4. If the of filter is present, its STDIN is closed, and the lpd server waits for it to exit. The exit status is used as described above. 5. The device (io_fd) is closed. 6. The job is marked as completed in the spool queue. 7. If the save_when_done flag is not specified, the job is removed. 66..66..66.. AAbbnnoorrmmaall TTeerrmmiinnaattiioonn Options used: +o mail_from=_M_a_i_l _f_r_o_m _u_s_e_r _n_a_m_e +o mail_operator_on_error=_M_a_i_l _t_o _o_p_e_r_a_t_o_r _o_n _e_r_r_o_r +o send_try# _M_a_x_i_m_u_m _P_r_i_n_t _o_r _T_r_a_n_s_f_e_r _A_t_t_e_m_p_t_s +o save_on_error _D_o _n_o_t _d_e_l_e_t_e _o_n _e_r_r_o_r +o send_failure_action=_A_c_t_i_o_n _o_n _F_a_i_l_u_r_e +o sendmail=_s_e_n_d_m_a_i_l _p_a_t_h _n_a_m_e _a_n_d _o_p_t_i_o_n_s +o stop_on_abort _S_t_o_p _p_r_o_c_e_s_s_i_n_g _q_u_e_u_e _o_n _f_i_l_t_e_r _a_b_o_r_t If the job processing terminates abnormally, the following sequence of events occurs: 1. The job is marked as having an error during processing. 2. The LPD server will attempt to kill all filters and other associated process by using a sequence of kill -INT, kill -QUIT, and finally kill -KILL operations. 3. If there is a mail_operator_on_error value, the specified operator will be mailed an error indication. The sendmail option specifies the pathname of the _s_e_n_d_m_a_i_l program and the options needed to have it read mail addresses from its standard input. For example, sendmail=/usr/sbin/sendmail -oi -t is a commonly used set of options. 4. The mail_from value specifies the user name used for mail origination. If not specified, the default is to use the print spool queue or printer name. 5. If there is a send_failure_action specified, then it is decoded and the corresponding action taken. If the value is remove, hold, abort, or retry, then the job is removed, held, aborted, or retried. If the value is |/program, the program is executed and the number of attempts are written to the filter STDIN. The exit status of the filter will be used to determine the consequent actions. That is, JSUCC (0) will be success, and the standard success action will be taken; JFAIL will cause retry, JREMOVE will cause the job to be removed, JHOLD will cause the job to be held, JABORT or other status will abort processing. 6. If the status is ABORT and the stop_on_abort flag is set, then further processing of jobs is terminated. The job is not removed from the queue. 7. If the error status indicates removal, and the save_on_error flag is clear then the job is removed from the spool queue. 8. If the error status indicates that no further operations should be performed on the queue, then the lpd server will stop processing jobs. 9. If the error code indicated that the job should be retried, and the send_try value is 0 or the number of attempts is less than the send_try value, then the job is retried. Between each attempt to transfer a job to a remote site. This pause will double after each attempt, reaching a maximum of max_connect_interval seconds. If max_connect_interval is 0, there is no limit on the interval value. 66..66..77.. LLPPDD SSppooooll QQuueeuuee PPrroocceessssiinngg Options used: +o lpd_force_poll=_F_o_r_c_e _L_P_D _t_o _p_e_r_i_o_d_i_c_a_l_l_y _p_o_l_l _p_r_i_n_t _q_u_e_u_e_s +o lpd_poll_time#_T_i_m_e _b_e_t_w_e_e_n _p_o_l_l_s +o max_servers_active#_M_a_x_i_m_u_m _n_u_m_b_e_r _o_f _a_c_t_i_v_e _s_e_r_v_e_r_s When the lpd server starts, it will fork a set of subserver processes, each which will handle an individual queue. If a system has a large number of queues, then this forking operation may result in the lpd server exhausting the process resources. To control this, the max_servers_active value restricts the number of active children to the specified value. If this value is 0, then 50% of the maximum system processes value will be used. Due to the limits on the number of processes, there may be times when a job is placed in a queue, but the lpd server is unable to start handling the job. When all of the children of the main lpd server have exited, the server starts a timer. After lpd_poll_time seconds, it will scan the queues, looking for jobs to process, and starts a process to service them. If it does not find any jobs it remains idle. The lpd_force_poll flag causes the server to periodically poll the queues. This is useful when there is a high possibility that jobs could fail to be printed due to high loads on the server. 66..77.. FFiilltteerr CCoommmmaanndd LLiinnee FFllaaggss Options used: +o bk_filter_options=_B_a_c_k_w_a_r_d_s _C_o_m_p_a_t_i_b_l_e _F_i_l_t_e_r _o_p_t_i_o_n_s +o bk_of_filter_options=_B_a_c_k_w_a_r_d_s _C_o_m_p_a_t_i_b_l_e _O_F _F_i_l_t_e_r _o_p_t_i_o_n_s +o bkf _B_a_c_k_w_a_r_d_s _C_o_m_p_a_t_i_b_l_e _F_i_l_t_e_r_s +o filter_ld_path=_F_i_l_t_e_r _L_D___L_I_B_R_A_R_Y___P_A_T_H _e_n_v_i_r_o_n_m_e_n_t +o filter_options=_F_i_l_t_e_r _o_p_t_i_o_n_s +o filter_path=_F_i_l_t_e_r _P_A_T_H _e_n_v_i_r_o_n_m_e_n_t +o of_filter_options=_O_F _F_i_l_t_e_r _o_p_t_i_o_n_s +o pass_env=_E_n_v_i_r_o_n_m_e_n_t _v_a_r_i_a_b_l_e_s _t_o _c_o_p_y _t_o _F_i_l_t_e_r _e_n_v_i_r_o_n_m_e_n_t +o pl#_l_i_n_e _c_o_u_n_t _f_o_r _p_a_g_e +o pw#_c_o_l_u_m_n _c_o_u_n_t _f_o_r _p_a_g_e +o px#_p_i_x_e_l _w_i_d_t_h _f_o_r _p_a_g_e +o py#_p_i_x_e_l _l_e_n_g_t_h _f_o_r _p_a_g_e A filter (or program) specification in the LPRng printcap database usually has the form: :option=| [flags] /path [arguments] :option=[flags] /path [arguments] The first case is used where the option value can be a string or filter, and the second where a program is always expected. The following procedure is used to run a filter program. The sequence of operations to run a filter is as follows: 1. The program must be specified with an absolute path name. 2. By default, the program is run as the user if invoked from a client program such as lpr, lpc, etc. If invoked from lpd, it is run as the server_user user (default daemon) configuration entry. 3. The _f_l_a_g_s control how the program is to be run. The following flags are supported: +o RROOOOTT This opens a horrible security loophole, as it will run the program as ROOT. To enable this option, you must set various compilation flags, and perform other arcane operations. This is deliberately done to make administrators read the warnings and admonitions. The alternative to ROOT is to have a setuid ROOT executable. Under NO circumstances should you run a shell script setuid ROOT, with general execute permissions on it. +o --$$ This very odd looking flag is used to suppress the addition of additional command line arguments specified by the value of filter_options to the program command line. 4. If the --$$ flag is not specified, the arguments determined by the value of the bkf (Berkeley LPD filter compatible flag) flag are added to the filter command line. If bkf is false the filter_options are added for OF filters and of_filter_options are added for non-OF filters; if it is true, then the bk_filter_options and bk_of_filter_options are added for OF and non-OF filters respectively. | | | |Option | DefaultValue | |filter_options | $C $F $H $J $L $P $Q $R $Z $a $c $d $e $f $h $i $j $k $l $n $p$r $s $w $x $y $-a | |of_filter_options | (same as filter_options) | |bk_filter_options | $P $w $l $x $y $F $c $L $i $J $C $0n $0h $-a | |bk_of_filter_options | $w $l $x $y | 5. By default, for programs that are not being invoked as print job file filters, the filter_options arguments are added. For print job filters, if the bkf flag is set, then the bk_filter_options and bk_of_filter_options entries are used. The default bk filter options are the same as originally used with the BSD LPR filters. For the of filter, either the of_filter_options or bk_of_filter_options arguments will be added. 6. The program arguments will then be scanned and interpreted. Arguments of the form $_l_e_t_t_e_r will be translated into values from the print job control file and/or printcap entry. The letters have the following meaning: | | | |Letter | TranslatedValue | |a | printcap af (accounting file name) | |b | job size (in K bytes) | |c | binary file (l format for print file) | |d | printcap cd or sd entry | |e | print job data file name (currently being processed) | |f | print job original name when spooled for printing (N info from control file) | |h | print job originating host (H info from control file) | |i | indent request (I info from control file) | |j | job number in spool queue | |k | print job control file name | |l | printcap pl (page length) | |m | printcap co | |n | user name (L info from control file) | |p | remote printer (when processing for bounce queue) | |r | remote host (when processing for bounce queue) | |s | printcap sf (status file) | |t | time in common UNIX format | |w | printcap pw (page width) | |x | printcap px (page x dimension) | |y | printcap py (page y dimension) | |F | print file format | |P | printer name | |S | printcap cm (comment field) | |Capital letter | Corresponding line from control file | |{key} | printcap value for key | 7. If there is no value for the specified argument, then the argument is removed from the list. If there is a value, the actual form of the substitution is controlled by additional flags as follows. Each entry in quotes is treated as a single value, as in /bin/sh. The $'x does not quote the value. Combinations of the various flags are allowed. For example, $-x would simply substitute the | | | |Form | TranslatedValue | | $x | '-x_v_a_l_u_e' | | $-x | '_v_a_l_u_e' | | $0x | -x '_v_a_l_u_e' | | $'x | -x _v_a_l_u_e | value for x, and then pass the whitespace separated components as individual arguments. This last form is useful for adding in additional flags on the command line. 8. The command line is parsed, metacharacters are ruthlessly stripped from all arguments and pathnames and replaced by _ (underscores), and an argument list suitable for the execve system call is formed. 9. A sanitized environment is set up for the program execution, with the following environment variables. | | | | USER | User name (client only) | | LOGNAME | L control file info | | HOME | Home directory (client only) | | LOGDIR | Home directory (client only) | | PATH | filter_path configuration information | | LD_LIBRARY_PATH | filter_ld_path configuration information | | SHELL | /bin/sh | | IFS | " \t" | | TZ | Time zone | | SPOOL_DIR | sd printcap info | | CONTROL_DIR | cd printcap info | | PRINTCAP_ENTRY | printcap info | | CONTROL | control file | 10. If the filter is to be run by a client program such as lpr, then the environment variables specified by the pass_env configuration or printcap option will be extracted from the environment, have any metacharacters removed, and then placed in the environment variable list. Commonly, the PGPPASS, PGPPASSFD, and PGPPATH are specified. 11. The program is started, with STDIN, STDOUT, and STDERR attached to the appropriate files or file descriptors. If none is specified, then they are attached to /dev/null. 66..88.. BBoouunnccee qquueeuueess aanndd ffiilltteerrss:: ccaavveeaattss There are a few situations in which a filter of a bounce queue will behave differently from an ordinary queue. 66..99.. TThhee llpprr --pp ffoorrmmaatt aanndd ::pprr ffiilltteerr The -p format doesn't behave as expected. Instead of lpr running pr, the job is forwarded to the lpd server, which will use the program specified by the :pf option. If you do not have the this program on your server, then job printing will fail. 66..1100.. CChhaannggiinngg FFiilltteerr FFoorrmmaattss Use the translate_format=oNoN... printcap option to simply rename formats in a print job before forwarding . Its value takes the form of old/new pairs of formats. For example: translate_format=xf The x format file will now be renamed with the f format before forwarding. 66..1111.. LLPPRRnngg SSuuppppoorrtteedd FFiilltteerrss There already exists a large library of ready-to-use filters. Some of them have LPRng-specific versions, which can be found at the ``LPRng ftp mirror sites''. 66..1111..11.. FFiilltteerr DDiissttrriibbuuttiioonn CCoonnvveennttiioonnss By convention, most filters are either totally standalone (very rare), or require a set of support files. There are two types of support files: per print queue configuration information and global support information. Since a print filter will execute with the current directory set to the spool queue directory, most filters expect that per print queue configuration information should be kept in the spool directory. Most _v_i_n_t_a_g_e filters insist on having these files _h_i_d_d_e_n with names such as .setup. This can make it difficult for administrators to determine where the configuration files are. It is strongly recommended that filters and information be placed in commonly accessible directories such as //uussrr//llooccaall//lliibb//ffiilltteerrss, and the executables in subdirectories. This allows the LPRng administrator to set the privileges on these directories such that only the lpd process can access them. Most of the LPRng supported filters can either be used as a if or of filter. The filter will examine the format type passed by the -F_X command line argument, and if it is o it will perform as an of filter. Alternatively, the filter will check the filename in the pathname by which is was invoked. If the name has the substring of in the filename, then it assumes it is to act as an of filter. This allows symbolic links to be made to a common filter executable, each of which corresponds to the filter name by which it is to be invoked. When a filter is invoked, it is passed a large number of options, many of which are totally ignored in filter operation. However, for many purposes it is necessary to provide options to the filters to tailor their operation to the particular spool queue needs. By convention, all LPRng supported filters use the -Tkey=value[,key=value] convention for specifying filter configuration option values. 66..1111..22.. llppff Source code: ``LPRng Distribution'' This filter is distributed as part of the LPRng source code, and has a very limited functionality. By default, it only translates \n to \r\n sequences, and detects the OF Filter Stop sequence when invoked as an OF filter. +o Options: -Tcrlf - suppress \n to \r\n translation 66..1122.. IIFFHHPP FFiilltteerr Source code: ``LPRng Distribution, ifhp-version.tgz'' This filter supports a wide variety of Hewlett-Packard printers, or to be more specific, printers which support the Hewlett-Packard PCL and/or PJL languages. In addition, they try to detect PostScript jobs and send the correct commands to the printers to enable PostScript rather than PJL operation. 66..1122..11.. PPrriinntteerr CCaappaabbiilliittiieess As explained in ``Setting Up Your Printer'', you can have a parallel (unidirectional), serial (bidirectional), or network (bidirectional) connection. When using a bidirectional connection, you can sometime obtain or gratuitously receive error and/or status information from the printer. Some printers will spontaneously generate error messages when printing a job on a bidirectional interface. Usually, though, it it necessary to force the printer to provide status in a reasonable format. Some printers have the capability of printing either PCL or PostScript; some require special setup commands and some will _a_u_t_o_s_e_n_s_e which type of job is being printed. If you are printing text, and not using a Page Description Language like PostScript or PCL, then you may want to download a font to the printer. This is especially the case when you are trying to print text files in a non-English font. Some printers will provide a _h_a_r_d_w_a_r_e page counter value when requested; however, the means of requesting differ from model to model. Sometimes you want to generate a special banner for a particular printer, and need to put in some dynamic information. While this can be done by the lpd server using the bp program specification, it turns out that non-LPRng systems which want to use the ifhp want to have the same facilities. Thus, you need to have some way to get the same effect as the bp option, but at the filter level. Having done lpd banner generation and printing, why not have the filter run an accounting script as well? At this point, I suspect that the reader is beginning to suspect that making a general purpose filter to support all of these possibilities is difficult. That is incorrect. It is eexxttrreemmeellyy difficult. 66..1122..22.. hhppiiff OOppttiioonnss These options are specified by the -Tkey=value [key=value]* on the command line. 66..1122..33.. PPaarraalllleell PPoorrtt PPrriinntteerr On a parallel port printer, you cannot get status, or do much besides set up the printer to either handle PostScript or do autosensee. The following is a typical printcap entry: | | | |Option | Purpose | |accounting=accounting_script_pathname | Invoke the accounting script with a subset of theoptions passed to the filter. In addition, the-bpagecount option indicates the number of pagesprinted for the job. | |autodetect=[on|off*] | The printer has or does not have job type autode-tect capability. Do not download fonts or try todetermine job type if autodetect is on. | |banner=[on|off*] | If banner is on, then the ifhp filter will attemptto print a banner using information passed on thecommand line or on the standard input. The titleoption can be used to specify additional titleinformation on the banner. See BANNERS below fordetails. | |cartridge=[*on|off] | (Alias for postscript)If cartridge is on, the printer has PostScript sup-port. The filter will try to determine if a job ispostscript and send Printer Job Language commandsto put the printer in PostScript mode. | |debug=debuglevel | Sets the debugging level; 2 is the default; alarger number causes more verbose error messages. | |defaultfont=fontname | Sets the default font to be downloaded; default isNONE. | |dev=/device or dev=host%port | Open the specified device or connection to remotehost; by default ifhp filter uses file descriptor 1(stdout). If the optional orig_port is specified,connections will be originated from this port.Some printers require that connections originatefrom a port in the range 1-1024. | |infostatus=[*on|off] | The PJL INFOSTATUS request is not supported on someHP printers. Use this to turn the status requestoff. Note that you cannot get real time reports ofthe printer status if you do this. This will alsosuppress getting pagecount information using thePJL facilities. | |forcepagecount=[on|off*] | If you have a printer that has PostScript pagecount information support, you can set infostatusto OFF and forcepagecount to ON. This will causethe PostScript facility to be used. If you setcartridge or postscript to OFF then this will notbe done. | |logall | Save all of the error and information messages fromthe printer in the log file. This is useful whenyou wish to examine returned status from theprinter. | |model=(C5M|III|IIID|IIISi|IV*) | The model of HP printer. C5M is Color 5M, III isHP LaserJet 3, IIID is HP LaserJet 3D, etc. Addi-tional printers may be added or defined at varioustimes - please consult the source for details.This selects various timing and format characteristic-tics. This is a desperation parameter for userswith antique or non-conforming PJL based equipment;read the source code for details on the particularpeculiarities. | |pagecount=[on*|off] | Get the hardware pagecounter value for accounting.Some printers such as the HP LJ4s do not have hard-ware support for pagecounters, and return bogusnumbers. Use this to suppress attempting to getvalid information. If your printer does supportPostScript, then you can get the page count valueusing PostScript by setting forcepagecount to ON. | |plp=[on|off*] | Return PLP status values on exit; by default LPRngstatus values are returned. | |postscript=[on*|off] | The printer has postscript support. | |quiet=[on|off*] | If set, do not report common status messages. | |retries=count | The number of times to retry connecting to theprinter. | |sleep=time | The number of seconds to wait before trying to con-nect to the printer. | |status=[*on|off] | When on, the printer is treated as a write onlydevice and is not queried for pagecount and statusinformation. Set status=OFF for parallel printers.If status is OFF, then the ifhp filter simply addsjob control language headers, fonts, and trailersto the jobs. | |stty=stty flags | if the output device is a serial line, set the linecharacters according to the stty flags. Theseflags are (most likely) identical to those avail-able with the stty(1) command on the host system. | |summary=[filename|host%port] | This option specifies that summary or informationalmessages should be placed in the specified file orsent, using the UDP protocol, to the indicated hostand port address. This allows remote monitoring ofthe printing and error activity. The undocumentedprogram included with the filter distribution is asimple program that can be used to perform the mon-itoring. | |sync=[*on|off] | Try to synchronize communications with printer.This will ensure that the printer has been reset,and no problems involving the previous job willresult. | |tbcp=[on|*off] | When invoked as an IF filter and transferring aPostScript job, the filter will use the AdobeTagged Binary Communications protocol. This allowsbinary data to be transferred and not interpretedas control information. | |title=line[/line]* | The title information is printed on the bannerpage; it consists of a list of / separated lineswhich are added to the banner information. | |wrap=[on|off*] | enables or disables line wrapping in PCLmode. | pr:.... options :of=/usr/local/lib/filters/ifhp -Tstatus=off :if=/usr/local/lib/filters/ifhp -Tstatus=off You might want to also look at the autodetect or postscript options. 66..1122..44.. PPrriinnttiinngg BBaannnneerrss By default, the ifhp filter when used as an OF filter will interpret the first line to it as a _s_h_o_r_t _b_a_n_n_e_r line, and use the information on this line to produce a PCL based banner. The short banner line should have the format: _c_l_a_s_s:_u_s_e_r_n_a_m_e Job: _j_o_b_i_n_f_o Date: _d_a_t_e_f_o_r_m_a_t Example: A:papowell Job: (stdin) Date: Sun Dec 14 07:13:34 PST 1997 This is produced by the default short banner line option value: bl=$-'C:$-'n Job: $-'J Date: $-'t If you want to suppress banner printing, then you need to suppress generation of this short banner line. If you want to have the lpd program to generate the default _l_o_n_g special banner, then you need to suppress ifhp from interpreting the information sent to is as banner information. Finally, you may want to have lpd invoke the bp (banner program) and have its output used as the banner. Here are the various possible ways: # no banner at all, use :sh: - suppress headers lp:.... :sh :of=/usr/local/lib/filters/ifhp # have ifhp generate banner from short banner input lp:.... :sb :of=/usr/local/lib/filters/ifhp # have LPD generate long banner, have of filter pass it lp:... :sb@ :of=/usr/local/lib/filters/ifhp -Tbanner=off # have LPD invoke bp banner generation program, have of filter pass it # bp programs require short banner on STDIN to work, so we need to # generate short banner lp:... :sb :bp=/usr/local/lib/filters/banner_program :of=/usr/local/lib/filters/ifhp -Tbanner=off The ifhp banner is generated in PCL, and uses the minimum PCL facilities. Since when you send a banner to an autosensing printer you cause it to enter the requested mode, the if filter (ifhp) will need to reset the printer to autosense mode. The ifhp filter automatically does this. If you want very fancy banners, the banner.sh (PCL) and psbanner.sh (PostScript) banner generating programs in the IFHP distribution make a good starting point. 66..1122..55.. EErrrroorr LLooggggiinngg Error logging and reporting is done by the ifhp filter as follows. 1. Messages are produced by the actions of the ifhp software. This are logged to the STDERR output of the filter. 2. Messages are produced by status returned from the printer, when the -Tstatus=on (default) option is enabled. These are classified according to the Hewlett-Packard Printer Job Language error status definitions, and logged to the STDERR output of the filter. 3. In addition to error messages, ongoing status messages are also produced. If the printcap entry has a ps=_s_t_a_t_u_s_f_i_l_e entry and the _s_t_a_t_u_s_f_i_l_e exists and is writeable, then the error and status messages will be written to the log file. 4. If the message concerns a serious matter or has been returned from the printer as an 'ALERT' in it, then the message can also be sent to a 'summaryfile'. This file can be either a file OR a UDP socket on a host. This is specified with the -Tsummary=_s_u_m_m_a_r_y_f_i_l_e option. For example, ifhp -Tsummary=taco%3000 on host taco. 5. If you do not want the filter to report status on its STDERR output, use the -Tquiet option to suppress this, or compile it with the -DQUIET option. 66..1122..66.. AAccccoouunnttiinngg IInnffoorrmmaattiioonn Doing printer accounting is not simple. Read ``LPRng Accounting'' for more information. In order to help aid in accounting, by default the ifhp filter will query the printer to get the current value of the hhaarrddwwaarree page counter value, if there is such a thing on the printer. Unfortunately, due to different types of printers and errors in their PJL, PCL, and PostScript implementations, several different methods need to be used. 1. Only a printer with a bidirectional port will return status, so you need to have a bidirectional connection. 2. If the printer is still printing a job, then getting the value of the hardware page counter will be useless; you need to wait until the printer is idle, i.e. - synchronize your operations with the printer. Unfortunately, some printers return an idle indication even when they are printing pages of the previous job. This means that the printer has to be polled, and only when it is idle aanndd the pagecounter value has been stable for a reasonable time (5 seconds?) can you trust the page counter value. This slows down job printing very seriously. Some of the newer PJL printers have a PJL TEOJ, or return end of job indication when the last page of a job has been printed. If you have this capability, you can speed up printing. 3. If your printer supports Hewlett-Packard Printer Job Language PJL INFO PAGECOUNT facility, then it will first be tried to get the page count. 4. If your printer does not return pagecount information using the PJL facility and it has PostScript support (default), then a small PostScript job will be sent to the printer requesting the _s_y_s_t_e_m_d_i_c_t _p_a_g_e_c_o_u_n_t_e_r value. Unfortunately, different implementations and versions of PostScript will need different programs. The PostScript Printer Definition file for the printer will have the correct script that is needed. The default script that is used is: /ps { print flush } def (\tPAGECOUNT ) ps statusdict begin pagecount end == flush 5. To confuse matters totally, some printers which can do PostScript interpretation do not support PJL _P_A_G_E_C_O_U_N_T reporting. You can use the PostScript method to get the pagecount information, but you cannot get status. 6. The pagecounter information is obtained at the start and end of processing a job, and is printed in the accounting file and also on File Descriptor 3 (if it is open). This information has the format: start -ppagecounter -Ff -kjob -uuser -hhost -R... end -ppages -qpagecounter -Ff -kjob -uuser -hhost -R... When we use the OF filter and/or banners, we will see the individual jobs bracketed by the OF filter records: start -p100 -Fo -kcfA100taco -uuser -hhost -R... start -p101 -Ff -kcfA100taco -uuser -hhost -R... end -p1 -q102 -Ff -kcfA100taco -uuser -hhost -R... start -p102 -Ff -kcfA100taco -uuser -hhost -R... We can use the various job numbers and other information to track page usage. The following are a selected set of printcap entries that can be used to get page counting information: # use defaults, try to get pagecount using all methods, wait for stable # value of pagecount before proceeding pr:... :of=/usr/local/lib/filter/ifhp # printer support PJL True End of Job and PAGECOUNT pr:... :of=/usr/local/lib/filter/ifhp -Ttrue_eoj=on # no PJL INFO status available, but you can get page count using postscript pr:... :of=/usr/local/lib/filter/ifhp -Tinfostatus=off,forcepagecount You should try connecting to your printer directly and testing the accounting facilities. You can do this by using the ifhp -Tdev=... facility. For example: ifhp '-Tdev=/dev/ttyb,stty=38400 -echo -crmod -raw -oddp \ -evenp ixon pass8 -ixany cbreak' -Tdebug=5 .tgz'' The lp_pipe family of filters was developed to act as a _n_e_t_w_o_r_k _p_i_p_e to network devices. They are largely replaced by the lp=host%port, facility. +o tcp-pipe: uses a tcp socket (OOBBSSOOLLEETTEEDD by lp=host%port), but good starting point if you have special device requirements; +o annex-pipe: supports annex terminal server. 66..1144.. aappssffiilltteerr FFiilltteerr Source code: ``LPRng Distribution, apsfilter-.tgz'' The apsfilter is basically a simple front end to the a2ps program (See: http://www-inf.enst.fr/~demaille/a2ps/ for details), and is an example of a _M_a_g_i_c_F_i_l_t_e_r that has powerful processing capability. The apsfilter program sets up options for the a2ps program and then invokes it. The a2ps program can convert just about any type of file into PostScript, and then by using the GhostScript facility can convert this to the output compatible with a particular printer. Combined with the LPRng qq and force_queuename options, we can set up virtual queues that do various types of reformatting. Here is a sample set of printcap entries: # seen by users - note that the queue name is put into control file, # and we then send it to the frontend@host queue for processing raw:qq:lp=frontend@host twoup:qq:lp=frontend@host landscape:qq:lp=frontend@host frontend:lp=frontend@host:force_queuename=raw # frontend does the job conversions and accounting frontend:server :lp=/dev/lp:force_queuename=raw :if=/usr/local/lib/filter/apsfilter 66..1155.. UUssiinngg yyoouurr oowwnn ffiilltteerrss If you already have a working setup, with its own specific filter programs, you might want to keep them. Or, you might want to write a set of your own. See the source code in the ``LPRng Distribution, FILTERS_LPRng-.tgz'' files for examples. 77.. SSppooooll QQuueeuueess aanndd FFiilleess When files are accepted by the lpd server for printing, they are stored in a spool queue directory, together with other files controlling the print operation. This section describes these files and how the LPRng software uses them. For descriptive purposes, we will use the following printcap entry as a guide: pr|alias :sd=/var/lpd/pr_public :cd=/var/lpd/pr 77..11.. SSppooooll QQuueeuuee aanndd CCoonnttrrooll QQuueeuuee +o sd=_S_p_o_o_l _q_u_e_u_e _d_i_r_e_c_t_o_r_y _n_a_m_e +o cd=_C_o_n_t_r_o_l _q_u_e_u_e _d_i_r_e_c_t_o_r_y _n_a_m_e The sd option in the printcap entry specifies the spool queue directory. If there is no sd entry or value, then the printer can only be used by the clients such as lpr to locate the destination for a print job. Normally, all information, files, etc., for a print queue is stored in the spool directory. However, some software packages such as the PC- NFS spooling package from Sun Microsystems originally required read/write access to the directory in order to create print jobs on behalf of the user. To prevent unauthorized or accidental tampering with LPRng operations, the cd (control directory) entry specifies that only the print job files should be placed in the spool queue, and that all the control and informational files should be in the control directory. By default, the cd value will be the same as the sd value unless explicitly overridden in the printcap entry. 77..22.. JJoobb SSttaattee Options used: +o ah _A_u_t_o_m_a_t_i_c_a_l_l_y _h_o_l_d _j_o_b_s A job can be in the following state: 1. Initial. This is the state during job submission. Jobs in the initial state do not have any status displayed for them. 2. Held. Once a job is submitted, it can either be printed or _h_e_l_d. The ah printcap option specifies that all jobs are automatically held on submission. The lpc release and lpc redo command will cause these jobs to be printed and the lprm command can remove these jobs. 3. Active. The job is being processed for printing or transfer to another queue. 4. Pending. Jobs which can be printed but are not active. 5. Error. Jobs which have encountered an error during printing. The lpc release and lpc redo command will cause these jobs to be printed and the lprm command can remove these jobs. 6. Done. Jobs which have completed printing, but which are not yet removed from the print queue. See the ``save_when_done'' flag for more information. The lprm command can remove these jobs. Normally the job sequences is initial, pending, active, and done. However, a job may be put in the error state by problems processing the job or by actions of the lpc command. 77..33.. PPrriinntteerr LLoocckk FFiillee When the lpd server starts printing, it will fork individual worker processes to service each queue. To prevent multiple processes from working on the same queue, a printer lock file with the cannonical spool queue name is used. In our example, the lock file would be: /var/lpd/pr/pr. The process ID of the currently active printer is stored in the lock file. By reading the lock file and testing to see if the process is still active, programs such as lpq can determine queue activity. Similarly, the worker process may need to create other processes to assist it. These in turn will create lock or temporary files in the spool directory as well. 77..44.. SSppooooll CCoonnttrrooll FFiillee The spool control file is used to control the operations of the spooler, and is in the spool or control directory. The file name has the form control._p_r_i_n_t_e_r; in our example, the control file would be: /var/lpd/pr/control.pr. The lpc program sends spool control requests to the lpd daemon, which updates the control file and then signals the appropriate spool server processes that an update has been performed. The control file contents have the form: key value The following keys and their values are currently supported. | | | | |Key | Values | Purpose | |printing_disabled | 0 or 1 | disable printing of jobs in queue | |spooling_disabled | 0 or 1 | disable placing jobs in queue | |holdall | 0 or 1 | hold jobs until released | |redirect | printer | transfer jobs to indicated printer | |class | glob expression | print only jobs whose class matches glob expression | |server_order | printer name list | preferred order of printer use | |debug | debugging options | debugging and tracing | The printing_disabled and spooling_disabled are managed using the lpc start, lpc stop, lpc enable and lpc disable commands. Similary, holdall is enabled and disabled by holdall and noholdall commands respectively. When holdall is enabled, jobs placed in the print queue will be held until they are explicitly released for printing by an lpc release command. The redirect entry is used to redirect or transfer jobs which are spooled to this queue to another queue, and is managed by the redirect command. The lpc redirect off removes the redirect entry from the control file. The class entry is similar in operation to the holdall, but allows jobs whose class identification matches the glob expression to be printed. This can be useful when you have special forms or paper required for a print job, and want to run only these jobs when the paper is in the printer. The server_order entry is created and updated for a multiple printer queue. It records the order in which printers should next be used for normal print operations. This allows _r_o_u_n_d _r_o_b_i_n use of printers, rather than having all jobs printed to the first printer in the list of printers. The debug entry is set by the lpc debug command, and is used to enable or disable debugging and tracing information for a spool queue. This facility is for diagnostic purposes only. 77..55.. LLoogg aanndd SSttaattuuss FFiilleess +o lf=_l_o_g _f_i_l_e _n_a_m_e _(_d_e_f_a_u_l_t_: _l_o_g_) +o max_log_file_size# _m_a_x_i_m_u_m _l_o_g _f_i_l_e _s_i_z_e _(_K_b_y_t_e_s_) +o min_log_file_size# _m_i_n_i_m_u_m _l_o_g _f_i_l_e _s_i_z_e _(_K_b_y_t_e_s_) +o max_status_line# _m_a_x_i_m_u_m _s_t_a_t_u_s _l_i_n_e _l_e_n_g_t_h _(_c_h_a_r_a_c_t_e_r_s_) +o max_status_size# _m_a_x_i_m_u_m _s_t_a_t_u_s _f_i_l_e _s_i_z_e _(_K_b_y_t_e_s_) +o min_status_size# _m_i_n_i_m_u_m _s_t_a_t_u_s _f_i_l_e _s_i_z_e _(_K_b_y_t_e_s_) +o ps=_f_i_l_t_e_r _s_t_a_t_u_s _f_i_l_e _n_a_m_e _(_d_e_f_a_u_l_t_: _s_t_a_t_u_s_) During operation, the lpd server records the current printing operations in the status._p_r_i_n_t_e_r file. For our example, this would be /var/lpd/pr/status.pr. In order to prevent this file from growing too large, the server will periodically truncate the file. The max_status_size configuration or printcap option sets the maximum size (in Kbytes) of the status file; if the file exceeds this, only the last min_status_size bytes or 25% of the maximum size (default if not specified) will be preserved. Similarly, the server logs its operations in the log file specified by the lf (log file) option (default is lf=log). The max_log_file_size value (default 0) specifies the maximum length of the log file in Kbytes. If this value is non-zero, then the log file is truncated to min_log_file_size bytes or 25% of the maximum file size. Again, the last portion of the log file is preserved. If the max_log_file_size value is 0, then the log file grows without limit. Some filters require an additional filter status file that they use for recording additional filter status or other operational information. The ps names this file, and it is passed to a print filter using the $s option (see ``Filter Command Line Flags''). The log file (lf) is opened and used as the STDERR output for filters and debugging information from the lpd server. When reporting status information, the length of line returned can be a problem. The max_status_line#79 option restricts the status line to a maximum of 79 characters. 77..66.. JJoobb CCoonnttrrooll FFiillee +o longnumber _l_o_n_g _j_o_b _n_u_m_b_e_r +o default_priority=_d_e_f_a_u_l_t _j_o_b _p_r_i_o_r_i_t_y A print job consists of a control file and one or more data files. ``RFC1179'' specifies the general format of these files and how they are to be transfered between servers. LPRng has extended the contents of the control files and the transfer protocol to provide a more powerful set of features, but has extensive provisions for backwards compatibility with non-LPRng software. A sample control file is shown below: Hastart4.astart.com J/tmp/file1 /tmp/file2 CA Lpapowell Ppapowell fdfA002230astart4.astart.com N/tmp/file1 UdfA002230astart4.astart.com fdfB002230astart4.astart.com N/tmp/file2 UdfB002230astart4.astart.com The first part of the control file contains general information generated by the lpr or other spooling program. The information lines start with an uppercase letter or digit. Some other spooling systems also start information lines with various punctuation marks such as underscores (_) or periods (.). Following this are a set of entries about each of the various files to be printed. These lines start with a lower case letter, followed by the print file name. The lower case letter is the _f_o_r_m_a_t to be used to process the file. See ``print file formats'' for more information about its use. The entries marked with * are used only by LPRng. N and U lines are associated with a print file. The N line is the original name of the print file. The U line originally was used to indicate that the named file was to be unlinked after printing. This information is now ignored by LPRng. These lines are always grouped with a print file entry. The names of control and data files follow a very strict pattern. Control files have the format cfX_n_u_m_b_e_rhhoosstt, where X is an upper case letter, _n_u_m_b_e_r is (usually) a 3 digit number, and hhoosstt is the host name. ``RFC1179'' restricted the total length of the control file name to 32 characters; LPRng has a much looser limit. | | | | |Key | Meaning | Generated By | |A | identifier * | LPRng internal | |C | class | lpr -C class | |D | date | lpr | |H | originating host | lpr | |I | indent | lpr -i indent | |J | jobname | lpr -J jobname (default: list of files) | |L | bnrname | lpr -U username | |N | filename | (see text) | |M | mailname | lpr -m mailname | |P | logname | lpr | |Q | queuename | lpr -Q | |R | accntname | lpr -R accntname | |S | slinkdata * | lpr | |T | prtitle | lpr -T prtitle | |U | unlnkfile | (see text) | |W | width | lpr -w width | |Z | zopts * | lpr -Z zopts | |1 | font1 | lpr -1 font1 | |2 | font2 | lpr -2 font2 | |3 | font3 | lpr -3 font3 | |4 | font4 | lpr -4 font4 | Data file names must follow the same pattern as the control file name, and have the format dfX_n_u_m_b_e_rhhoosstt. The X can be in the range A-Za-z, allowing at most 52 data files for a job. The _n_u_m_b_e_r and hhoosstt must be identical to the corresponding control file. By convention, LPRng uses the X of the control file name to set a priority for the job. A job with control file name cfA... will have _l_o_w_e_r format than a job with format cfB..., and so forth. The lpr program uses the first letter of the class name or an explicit priority indication to set the letter value. If none of these are specified, then the default_priority value from the configuration or printcap entry is used. The job number is usually a 3 digit value. However, in systems where a large number of jobs are spooled and need to be kept for printing at scheduled times, this can lead to problems. The longnumber option will use 6 digit job numbers. This must be used with care when operating with non-LPRng software. 77..77.. JJoobb HHoolldd FFiillee Associated with each control file is a hold file that has additional information controlling the printing operations. The entries in this file have the form: key [value] The following is an example of a hold file: server 0 subserver 0 attempt 3 error cannot open printer hold 0 priority 0 remove 0 routed 0 The server and subserver entry records the process ID of the server process and the subserver process that is printing the job. The attempt field records the total number of attempts to print the job. The error field records any error that would prevent the job from being printed. This information is reported by the lpq program. The hold field is non-zero when the lpc hold command is used to explicitly prevent the job from being printed; lpc release will clear the field and allow the job to be printed. The priority field is modified by the lpc topq command and is used to provide an overriding priority to printing the file. The remove field is non-zero when the file has been printed and should be removed. The routed field is used to indicate that there is routing information present in the hold file, and that special handling is needed. The routing information is provided by a ``routing filter''. The information is recorded by information in the hold file. The following is an example of routing information: active 0 attempt 0 done 0 hold 0 priority 0 remove 0 routed 880892602 route dest t1 route ident papowell@astart4+705.1 route error route copies 1 route copy_done 0 route status 0 route active 0 route attempt 0 route done 0 route hold 0 route sequence 0 route priority B route CB route end route dest t1 route ident papowell@astart4+705.2 route error route copies 0 route copy_done 0 route status 0 route active 0 route attempt 0 route done 0 route hold 0 route sequence 1 route end Routing information lines start with route followed by individual routing entry information. The route dest, copies, priority, and Xnnnn entries are derived from the output of the router program; other fields are used during the printing process. The copy_done records the numbers of copies done, while the done records that the entry has been completed. The status is the process ID of the server process doing the printing. The output from route filter that generated the above file was: dest t1 copies 1 priority B CB end dest t1 end 77..88.. JJoobb IIddeennttiiffiieerr Options: +o use_identifier _p_u_t _j_o_b _i_d_e_n_t_i_f_i_e_r _i_n _c_o_n_t_r_o_l _f_i_l_e For each job in a spool queue, the LPRng software creates a unique identifier. This identifier is recorded in the control file A line. It can be used by the various client programs for identifying jobs, and is displayed by the lpq program as status information. 88.. //eettcc//llppdd..ccoonnff CCoonnffiigguurraattiioonn FFiillee The values in the LPRng configuration file (default: /etc/lpd.conf) specify values for global options and default values for printcap options. See the man pages for lpd.conf(5) and printcap(5) for a complete list of configuration variables and their effects. 88..11.. CCoonnffiigguurraattiioonn FFiillee FFoorrmmaatt The LPRng distribution contains a template lpd.conf file which can be installed as /etc/lpd.conf. The configuration file has the following format: # Default version of the lpd.conf file # ae=jobend $H $n $P $k $b $t # allow_getenv # ar # architecture # as=jobstart $H $n $P $k $b $t # bk_filter_options=$P $w $l $x $y $F $c $L $i $J $C $0n $0h $-a # bk_of_filter_options=$w $l $x $y # bl=$-'C:$-'n Job: $-'J Date: $-'t # check_for_nonprintable check_for_nonprintable@ # client_auth_command ... The file uses the same notation for ``printcap'' entries, but does not use the : (colon) separator. A line starting with # is a comment. To change the default value of an option, remove the comment character and edit the entry. In the above example, the default value (1 or TRUE) for check_for_nonprintable has been changed to 0 or off. To force the lpd server to use the new options, use the lpc reread command. As for printcap entries, the %X combinations are interpreted when a configuration entry is used for configuration or defaults, and can be used to do site and host dependent customization. This interpolation is done when the default or configuration value is used in a printcap context. See ``Missing Details'' for more information. 88..22.. OObbttaaiinniinngg CCoonnffiigguurraattiioonn IInnffoorrmmaattiioonn The location of the configuration file is compiled into the LPRng software. The config_file entry in the compilation defaults is normally set to search for configuration information in the following files: config_file=/etc/lpd.conf:/usr/etc/lpd.conf To change any of the config_file specifications, the the LPRng/src/common/vars.c file will need to be modified and the LPRng software recompiled. In addition, LPRng has a special _d_e_b_u_g mode. When compiled with the -DGET_ENV option enabled, this sets the value of the allow_getenv option to 1. LPRng can then use the value of the LPD_CONF environment variable instead of the compiled in config_file value. TThhiiss iiss aa ppoossssiibbllee sseeccuurriittyy lloooopphhoollee,, aanndd sshhoouulldd nnoott bbee uusseedd wwhheenn rruunnnniinngg SSEETTUUIIDD RROOOOTT oorr aass RROOOOTT.. To enable this option, see the Test Version comments in the LPRng/src/Makefile. 88..33.. UUsseeffuull CCoonnffiigguurraattiioonn OOppttiioonnss The following variables are used to set default behavior for the LPRng software, or are commonly used for configuration of LPRng operations. 88..33..11.. ddeeffaauulltt__ffoorrmmaatt Default format for printing. Usually, default_format=f, but setting it to default_format=l will cause all files spooled by lpr to be spooled as binary files. 88..33..22.. ddeeffaauulltt__ppeerrmmiissssiioonn==AACCCCEEPPTT The default permissions to use when checking for printing or other permissions. 88..33..33.. ddeeffaauulltt__pprriioorriittyy==AA The default priority for a print job. 88..33..44.. ddeeffaauulltt__rreemmoottee__hhoosstt==llooccaallhhoosstt The default lpd server host. 88..33..55.. ddeeffaauulltt__ttmmpp__ddiirr==//ttmmpp The default directory for temporary files. This option can be used to specify a default printer. If no value is given (default), the first printer in the printcap file will be used when no printer is specified. 88..33..66.. ddoommaaiinn__nnaammee==ddoommaaiinn..nnaammee You will only need to set this if LPRng can't determine your hosts domain name itself. This is usually a desperation option when DNS or some other database system is not available. 99.. TThhee //eettcc//llppdd..ppeerrmmss PPeerrmmiissssiioonnss FFiillee This file is used to specify the restrictions on the use of the LPRng software, printers, and other facilities. The model used for permission granting is similar that used in the rule set used by packet filters. An incoming server request is tested against a list of rules, and the first match that is found determines the action to be taken. The following is an example of a lpd.perms file. # allow root on server to control jobs ACCEPT SERVICE=C SERVER REMOTEUSER=root REJECT SERVICE=C # # allow same user on originating host to remove a job ACCEPT SERVICE=M SAMEHOST SAMEUSER # allow root on server to remove a job ACCEPT SERVICE=M SERVER REMOTEUSER=root REJECT SERVICE=M # all other operations allowed DEFAULT ACCEPT The structure of the lpd.perms file was inspired by network packet filter configuration files. When the LPD server gets a request from a remote client program, it performs the checks specified by the rules in the lpd.perms to decide whether to accept or reject the request. A rule will ACCEPT or REJECT a request if all of the patterns specified in the rule match. If there is a match failure, the next rule in sequence will be applied. If all of the rules are exhausted, then the last specified default authorization will be used. The sense of a pattern match can be inverted using the NOT keyword. For example, the rules with ACCEPT NOT USER=john,bill succeeds only if USER is defined and the USER value is not john or bill. The following patterns and matching are applied. | | | |Keyword | Match | |DEFAULT | default result | |SERVICE | lpC Status and User, lpR, lprM, lpQ request | |USER | user name in print job | |REMOTEUSER | user making request | |HOST | host name in print job | |REMOTEHOST | host making request | |IP | IP address and mask of host in print job | |REMOTEIP | IP address and mask of host making request | |PORT | TCP/IP port of host making request | |SAMEUSER | USER and REMOTEUSER same | |SAMEHOST | HOST and REMOTEHOST same | |SERVER | request originates on lpd server | |FORWARD | destination of job is not host | |GROUP | USER is in the specified group | |LPC | LPC command requested | |REMOTEGROUP | REMOTEUSER is in the specified group | |CONTROLLINE | match a line in control file | |AUTH | authentication type | |AUTHUSER | authenticated user | |AUTHFROM | authenticated forwarder | |AUTHJOB | authenticated job in queue | Most of the patterns can be lists of alternative values to match, and can even contain wild cards. The full details of the rules and keywords are detailed in the lpd.conf(5) man page. 99..11.. IInnffoorrmmaattiioonn ffoorr mmaattcchhiinngg In order to do matching, the lpd server obtains and sets up the following information: 1. If the request is coming over a network connection, then the IP address (REMOTEIP) port (PORT) of the source of the connection and FQDN of the remote host (REMOTEHOST) are obtained and the indicated values are set. To be specific, the IP address of the remote host is obtained using getpeername(). The gethostbyaddr() is used to look up the host's fully qualified domain name, which is then assigned to the REMOTEHOST value. The REMOTEIP value is the _s_e_t or _l_i_s_t of IP addresses that could be used by this host. This is possible in the IPV6 environment. 2. If the request contains the name of the user, then REMOTEUSER is assigned the name. 3. If the request contains the name of the printer, then PRINTER is assigned the name. 4. If a print job is being printed, then the USER, HOST, IP, and PRINTER are set to the user name, host, and printer information in the control file for the print job. To be specific, the HOST entry in the control file is used by gethostbyname() to get the fully qualified domain name of the host. The IP value is assigned a _s_e_t or _l_i_s_t of IP addresses that could be used by this host. 5. If one of the optional authentication methods is being used, (see ``Authentication and Encryption''), then AUTH is true and AUTHTYPE is set to the type of authentication used. AUTHUSER to the authenticated originating user of the request and AUTHFROM is when the originating program is a server. The AUTHSAMEUSER will be true when the remote client authentication information matches the authentication information used to create the job on the server. The AUTHJOB will be true when checking for job permissions and the job has been authenticated. 99..22.. PPeerrmmiissssiioonn CChheecckkss When a connection is made to the lpd server, the originating site's IP address and hostname are determined, and a check with SERVICE=X is made. The REMOTEHOST, REMOTEIP, and PORT will be defined for the purposes of this check. If the result is to accept the connection, then the request is then read from the connection, and the SERVICE, REMOTEUSER and PRINTER will be defined. A further check is performed to determine if the service request would be accepted. When performing a service activity and a particular job is to be acted on, the USER, HOST, and other control file information will be available, and a further check can be performed. If a rule is specified and the particular value is not defined, then a rule will fail to match. 99..33.. MMaattcchh PPrroocceedduurree key=pattern substring match key=pattern1,pattern2,pattern3,... glob and exact key=IP1/mask1,IP2/mask2,... IP address Each of the indicated values is matched against a list of patterns. The following types of matches are used: 1. substring match. The indicated entry is present as a substring in the pattern. 2. GLOB matches. The pattern is interpreted as a GLOB style pattern, where * matches 0 or more characters, and ? matches a single character, and [L-H] specifies a range of characters from L to H, in ASCII order. 3. IP address match. The address must be specified in the standard nn.nn.nn.nn format. The mask must be either an integer number corresponding to the number of significant bits, or in the standard nn.nn.nn.nn format. Addresses are compared by doing ( IPaddr XOR IP ) AND mask If the result is 0, then a match results. Note that there may be one or more addresses being checked for; this can occur when a host may have multiple IP addresses assigned to it. 4. integer range match. The pattern has the form low-high, where low and high are integer numbers. The match succeeds if the value is in the specified range. 5. Same IP Address Match. This compares two lists of IP addresses; a match is found when there is one or more common addresses. 99..33..11.. DDEEFFAAUULLTT DEFAULT ACCEPT DEFAULT REJECT The DEFAULT rule specifies the default if no rule matches. Normally, there is one DEFAULT entry in a permissions file. 99..33..22.. SSEERRVVIICCEE Match type: substring The SERVICE key is based on the type of request. | | | |Key | Request | |C | LPC Control Request | |M | LPRM Removal Request | |P | Job Printing | |Q | LPQ Status Request | |R | LPR Job Transfer | |S | LPC Status Request | |X | Connection Request | Each of the above codes corresponds either directly to the user command, or a set of subcommands. All the LPC subcommands are SERVICE=C; status commands such as lpc status, printcap, active, or lpd are SERVICE=S commands as well. 99..33..33.. UUSSEERR Match type: GLOB The USER information is taken from the P (person or logname) information in the print job control file. 99..33..44.. RREEMMOOTTEEUUSSEERR Match type: GLOB The REMOTEUSER information is taken from the user information sent with a service request. Note that one of the flaws of ``RFC1179'' is that an LPQ (print status) request does not provide a REMOTEUSER name. 99..33..55.. HHOOSSTT Match type: GLOB The HOST information is taken from the H (host) information in the print job control file. 99..33..66.. RREEMMOOTTEEHHOOSSTT Match type: GLOB The REMOTEHOST information is obtained by doing a reverse IP name lookup on the remote host address. If there is no FQDN available, then the IP address in text form will be used. 99..33..77.. PPOORRTT Match type: integer range The PORT value is obtained from the originating port of the TCP/IP connection. The match succeeds if it is in the specified range. 99..33..88.. IIPP Match type: IPaddr The IP information is obtained by doing a DNS lookup on the H (host) information in the control file. If there is no host information, the IP address is undefined. Note that for a single host name there may be multiple IP addresses; address matches are performed against the list of addresses and succeeds if there is one or more individual address matches. 99..33..99.. RREEMMOOTTEEIIPP Match type: IPaddr The REMOTEIP information is the IP address of the host making the service request. Note that the REMOTEIP value is obtained by using the gethostbyaddr lookup to obtain the DNS information for the remote host. This information may include multiple IP addresses; address matches are performed against the list of addresses and succeeds if there is one or more individual address matches. 99..33..1100.. LLPPCC Match type: GLOB If you are doing an LPC command, this matches the command. This allows the following permissions line to be used: #allow remoteuser admin on server to use LPC topq and hold ACCEPT LPC=topq,hold SERVER REMOTEUSER=x 99..33..1111.. SSAAMMEEUUSSEERR Match type: exact string match Both the REMOTEUSER and USER information must be present and identical. 99..33..1122.. SSAAMMEEHHOOSSTT Match type: Same IP Address The REMOTEHOST and HOST address lists are checked; if there is a common value the match succeeds. 99..33..1133.. SSEERRVVEERR Match type: Same IP Address One of the REMOTEHOST addresses must be the same as one of the addresses of the lpd server host, or must be one of the addresses found by looking up the localhost name using gethostbyname(). 99..33..1144.. FFOORRWWAARRDD Match type: Address Match The list of REMOTEHOST and HOST addresses must not have a common entry. This is identical to NOT SAMEHOST. This is usually the case when a remote lpd server is forwarding jobs to the lpd server. 99..33..1155.. GGRROOUUPP Match type: modified GLOB If the pattern does not start with a @ character, then the USER information must be present and the USER must be present in one of the groups in /etc/group or whatever permissions mechanism is used to determine group ownership which matches the GLOB pattern. If the pattern starts with a @ character, then the USER information must be present and the user must be in the specified netgroup. This match will be performed only if the netgroup mechanism is supported on the system and the specified netgroup exists. No wildcard match will be done for netgroups. 99..33..1166.. RREEMMOOTTEEGGRROOUUPP The same rules as for GROUP, but using the REMOTEUSER value. 99..33..1177.. CCOONNTTRROOLLLLIINNEE Match type: GLOB A CONTROLLINE pattern has the form X=pattern1,pattern2,... X is a single upper case letter. The corresponding line must be present in a control file, and the pattern is applied to the line contents. This pattern can be used to select only files with specific control file information for printing. 99..33..1188.. AAUUTTHH Match type: GLOB The AUTH value can be NONE, indicating that no authentication was done. If authentication was done, then AUTH=USER checks to see if there was user information, and AUTH=FWD checks to see if there was forwarding system identification. 99..33..1199.. AAUUTTHHUUSSEERR Match type: GLOB If AUTH=USER check succeeds, the AUTHUSER rule will check to see if the user identification matches the pattern. 99..33..2200.. FFWWDDUUSSEERR Match type: GLOB If AUTH=FWD check succeeds, the FWDUSER rule will check to see if the forwarding system identification matches the pattern. 99..33..2211.. IIFFIIPP Match type: IPmatch, but for IPV6 as well as IPV4 There is a subtle problem with names and IP addresses which are obtained for 'multi-homed hosts', i.e. - those with multiple ethernet interfaces, and for IPV6 (IP Version 6), in which a host can have multiple addresses, and for the normal host which can have both a short name and a fully qualified domain name. The IFIP (interface IP) field can be used to check the IP address of the origination of the request, as reported by the information returned by the accept() system call. Note that this information may be IPV4 or IPV6 information, depending on the origination of the system. This information is used by gethostbyaddr() to obtain the originating host fully qualified domain name (FQDN) and set of IP addresses. Note that this FQDN will be for the originating interface, and may not be the cannonical host name. Some systems which use the Domain Name Server (DNS) system may add the cannonical system name as an alias. 99..44.. PPeerrmmiissssiioonn FFiillee LLooccaattiioonn Options used: +o perms_path= _d_i_r_e_c_t_o_r_y _p_a_t_h _l_i_s_t The perms_path= configuration variable specifies the location of the default permissions file. The default value is: perms_path=/etc/lpd.perms:/usr/etc/lpd.perms The lpd.perms file can be obtained by running a program, in a similar manner to the /etc/printcap file. See ``Filters'' for details on how the program would be invoked. For example, assume the configuration information specified: perms_path=|/usr/local/libexec/get_perms Then the get_perms program would be invoked with STDIN attached to /dev/null and the complete set of permission information would be read from its STDOUT. 99..55.. EExxaammppllee PPeerrmmiissssiioonn FFiillee # allow root on server to control jobs ACCEPT SERVICE=C SERVER REMOTEUSER=root REJECT SERVICE=C # # allow same user on originating host to remove a job ACCEPT SERVICE=M SAMEHOST SAMEUSER # allow root on server to remove a job ACCEPT SERVICE=M SERVER REMOTEUSER=root REJECT SERVICE=M # all other operations allowed DEFAULT ACCEPT In the above sample, we first specify that lpC commands from user root on the lpd server will be accepted. This is traditionally the way that most lpc commands operate. Next, we reject any other lpc requests. We accept lprM requests from the host and user that submitted the job, as well as from root on the server, and reject any others. Finally, all other types of commands (lpq, lpr) are allowed by default. 99..66.. CCoommpplleexx PPeerrmmiissssiioonn CChheecckkiinngg One of the more useful types of permission checking is to restrict access to your printers from users outside your networks. The IP pattern can specify a list of IP addresses and netmasks to apply to them. For example IP=10.3.4.0/24 would match all hosts with the IP addresses IP=10.3.4.0 to IP=10.3.4.255. Similarly, the HOST pattern can specify a set of hostnames or patterns to match against based on the GLOB notation. For example REMOTEHOST=*.astart.com would match all hosts with a DNS entry which ended with astart.com. The NOT keyword reverses the match sense. For example REJECT NOT REMOTEHOST=*.astart.com,*.murpy.com would reject all requests from hosts which did not have a DNS entry ending in astart.com or murphy.com. 99..77.. MMoorree EExxaammpplleess The following is a more complex lpd.perms file. # All operations allowed except those specifically forbidden DEFAULT ACCEPT #Reject connections which do not originate from hosts with an # address on 130.191.0.0 or from localhost, # or name is not assigned to Engineering pc's REJECT SERVICE=X NOT IFIP=130.191.0.0/16,127.0.0.1/32 REJECT SERVICE=X NOT REMOTEHOST=engpc* #Do not allow anybody but root or papowell on #astart1.astart.com or the server to use control #facilities. ACCEPT SERVICE=C SERVER REMOTEUSER=root ACCEPT SERVICE=C REMOTEHOST=astart1.astart.com REMOTEUSER=papowell #Allow root on talker.astart.com to control printer hpjet ACCEPT SERVICE=C HOST=talker.astart.com PRINTER=hpjet REMOTEUSER=root #Reject all others REJECT SERVICE=C #Do not allow forwarded jobs or requests REJECT SERVICE=R,C,M FORWARD # allow same user on originating host to remove a job ACCEPT SERVICE=M SAMEHOST SAMEUSER # allow root on server to remove a job ACCEPT SERVICE=M SERVER REMOTEUSER=root 1100.. RRuunnnniinngg tthhee ssooffttwwaarree 1100..11.. LLPPRRnngg''ss lliittttllee hheellppeerr:: cchheecckkppcc The program checkpc (check printcap file) is one of the most useful utilities in the LPRng package. It will read all the configuration files, printcap files and tests whether devices are set up correctly. Optionally, it will also set the permissions for spool directories and device files. Additionally, it will truncate the accounting and log files to a maximum size. Another use for checkpc is to remove old entries from queue directories. For a new installation, you will want to run checkpc -f to set the permissions right. The -f flag instructs the program to correct file permissions. If you don't run this as root, you'll receive a warning about that fact and any cchhoowwnn((22)) calls will (most likely) fail. The program reports everything it changes. Since it isn't too clever about some things (visit the man page), you should keep an eye on the output, and run it again if needed. If it keeps failing, change the permissions yourself. These are the permissions of my spool directory: drwx--S--- 2 lp lp 1024 Jul 22 21:15 ./ drwxr-xr-x 16 root root 1024 May 29 21:55 ../ -rw------- 1 lp lp 10222 Jul 23 05:32 acct -rw------- 1 lp lp 0 Feb 14 21:14 control.lp1 -rw------- 1 lp lp 10229 Jul 23 05:32 log -rw------- 1 lp lp 5 Jul 22 21:13 lp1 -rw------- 1 lp lp 9064 Jul 22 21:15 status.lp1 -rw------- 1 lp lp 5 Jul 22 21:13 unspooler.lp1 And this is lpd's master directory: drwx--S--- 2 lp lp 1024 May 11 18:44 ./ drwxr-xr-x 16 root root 1024 May 29 21:55 ../ -rw------- 1 lp lp 0 Feb 18 07:05 lpd.lock.duff -rw------- 1 lp lp 3 Jul 13 22:42 lpd.lock.duff.printer -rw------- 1 lp lp 0 Apr 1 22:40 lpd.log.duff Later, you will want to use checkpc for the daily maintenance of your system. I have this line in user lp's crontab: 32 5 * * * checkpc -t 10K -A3 -r >/dev/null 2>&1 This job will: 1. truncate all log and accounting files to 10KB (-t 10K). Actually, it will keep the last 10K from the file, starting on a complete line. 2. remove all stale files older than three days (-A3 -r). I'm redirecting output to /dev/null, because checkpc is a little noisy to my taste. (But too noisy is better than too silent :) 1100..22.. SSttaarrttiinngg tthhee ddaaeemmoonn Now comes the moment of truth: will it work? (I hope so, otherwise it means there are errors here.) Where should I run the daemon? In order to work, vanilla LPR needs to be run on all computers on the network. This is because a job is first transmitted to the local lpd, and then (if needed) to the remote host. LPRng eliminates the local lpd from this chain, and connects directly to the remote daemon (except in the case of a bounce queue). Therefore, you won't need to start a daemon on all machines. In short: where do you need the daemon? Only on those machines where you have spool directories. Almost there... These are the last steps in the installation: +o Kill your old lpd/lpsched. +o Start the newly installed lpd program. +o Print a sample file using the new lpr: lpr /etc/printcap If it works, you can remove your old printing software, and change your system startup files to run the new daemon automatically. Then, read the rest of the documentation to build whatever complex configuration you need. 1111.. AAccccoouunnttiinngg The LPRng method for doing accounting is based on experiences in a Academic environment, where avoiding printing accounting procedures has long been practiced. While the LPRng procedures are not bombproof, they do provide a wide range of facilities, with various degrees of trust built into them. 1111..11.. PPrriinntteerr AAccccoouunnttiinngg RReeaalliittyy CChheecckk The following was written by Patrick Powell in response to the expressions of frustration that are periodically vented in the ``lprng@iona.ie'' mailing list. While this addresses the use of a particular set of printer filters, i.e. - the ``ifhp'' set, the comments are appropriate to other issues. In Academic institutions, avoiding printing accounting has been regarded as a challenge, an ongoing game of fat cat and poor starving mouse, between the Administration and the downtrodden, poor, overcharged student. The following is a lighthearted ramble down the dark lane of printing accounting. We will disregard the fact that if most students put as much effort into their studies as in finding ways to avoid accounting procedures then they would be Rhodes Scholar material, but I digress... The accounting procedures put into the LPRng and the hpif filters may appear to be extraordinarily complex, but believe me, they are not. Firstly, we make the assumption that the printer has some sort of non- volatile page counter mechanism that is reliable and impervious to power on/off cycles. Without this mechanism the enterprising student ummm... user will simply turn off the printer. Software that prescans jobs for line counts and pages is notoriously unreliable, given even the most modest efforts of users to hide these procedures. The cost of running a PostScript simulator simply to do accounting has its flaws; without ensuring that the simulator has all of the interesting security loopholes closed, such as opening files, etc., it can become a trap door to hell for the system administrator. Secondly, we must make the assumption that the student... uhhh... user will not be able to tinker with the page counter mechanism, i.e.- they will not be able to roll back the odometer on the printer, FOR THE DURATION OF A SINGLE JOB. I will digress and point out that a student actually did this for a challenge; it only took him a couple of weeks of study and a fully equipped microcontroller lab, and two (2) laser printers which he ruined in the experiment. HP was not amused when we sent them back under warranty, claiming that this our 'normal lab usage.' Lastly, you should not mind a small amount of pilferage, or a few pages here and there being charged to the wrong account. HHooww DDooeess IItt WWoorrkk?? The ifhp filter records the page counter value at the start and end of each part of a print job. Each record has the form: start -ppagecounter -Ff -kjob -uuser -hhost -R... end -ppages -qpagecounter -Ff -kjob -uuser -hhost -R... When we use the OF filter and/or banners, we will see the individual jobs bracketed by the OF filter records: start -p100 -Fo -kcfA100taco -uuser -hhost -R... start -p101 -Ff -kcfA100taco -uuser -hhost -R... end -p1 -q102 -Ff -kcfA100taco -uuser -hhost -R... start -p102 -Ff -kcfA100taco -uuser -hhost -R... end -p3 -q105 -Ff -kcfA100taco -uuser -hhost -R... end -p5 -q105 -Fo -kcfA100taco -uuser -hhost -R... It should be clear from the above that all we need to do is to add up the values for the -Fo (OF) filter lines and we are done. Unfortunately, this is too simplistic. If for some reason the job is killed or terminates due to error conditions, the OF filter may not get to finish its work. Thus, we may see the following: start -p100 -Fo -kcfA100taco -uuser -hhost -R... start -p101 -Ff -kcfA100taco -uuser -hhost -R... start -p110 -Fo -kcfA101taco -uuser -hhost -R... This is a clear indication that the user's job has been terminated. In this case we need to use the differences between pagecounters of the start records to do accounting. There is a caveat to all of this; that is the problem of the last dead job in the list. If the last line in the accounting file is: start -p110 -Fo -kcfA101taco -uuser -hhost -R... is the last job finished or did it abort? WWhhoo UUsseedd UUpp 22000000 PPaaggeess ooff PPaappeerr TTooddaayy?? Now we move on to the problem of real time accounting. Due to limited budgets, etc., many institutions would like to strictly enforce limits on paper use by students. As jobs are printed their accounts should be docked for the amount of paper use. One way to do this is to have an external accounting procedure update a shared database. The ifhp filter has provision for a shell script to be called at the end of print job; this is done by both the OF and IF filter. Thus, we can blithely assume that there is a central database carefully getting updates from the LPRng software, probably from dozens of different printers, and updating the accounting information. The first question to be asked is simple: is this worth it? Perhaps doing accounting as a batch job once an hour/four times a day/once a day is cheaper than building an running such a database. If it costs $5K/year for the database software, you might just consider ignoring the 10,000 pages that get lost in the shuffle and use a simple set of awk/sed/perl scripts to update a database once an hour. BBAADD JJOOBBSS -- WWhhoo DDoo WWee BBiillll?? We inevitably run into an interesting question: what happens if a job does not complete correctly? If you use the completion of the OF filter as a success status, I have to point out that many students... ummm... users soon find ways to send jobs to the printer that will cause it to lock up after their output has been printed. These jobs require power cycling of the printer and restarting the filter; a bit extreme, perhaps, but it has happened. I suggest that you simply adopt a 'bill to last user of record' attitude, using the pagecount information as follows: start OF -- starting point for THIS job start IF -- nice information, but not useful start IF -- end OF -- ending point for this job - can record infomation start OF -- if no end OF for previous job, then treat as end OF and update accounting. Now somebody is sure to complain that they got charged for a bunch of pages that they did not use. This is inevitable; always carry a can of oil for the squeaky wheels. I might make the observation that once is accident, twice is coincidence, but three times is malice; be wary of the constant complainer and check out not only him or her but also their co-workers. HHooww DDoo WWee UUppddaattee tthhee DDaattaabbaassee?? I suggest that database update be done as follows: You maintain a 'last page reported' counter for each printer in the database. When a successful job reports in, check to see that pagecount + joblength == newpagecount; If this is not the case, then you have had a some unsuccessful jobs. In this case I strongly recommend that you have a means to request the accounting reporting program to go back through the accounting file and find the last report for the page counter value and try to backtrack through the accounting files. The accounting file is one of the first things to be attacked by students... Ummm... users. It should NOT be kept on an NFS exported or mounted file system. It should be carefully pruned and copied, perhaps on an hourly basis. Now some administrators have fallen in love with network based printers; do not believe ANYTHING that comes over a network connection without some form of authentication; PGP has some very nice Public Key mechansims for handling this. This is a major weakness in using a database for keeping track of accounting - a weak authentication mechanism may lead to denial of service attacks by students flooding the database with bogus print usage reports; suddenly NOBODY can print and the administrator is driven to turning off accounting. Good luck. I am never surprised when I encounter yet another wrinkle in this area. Patrick ("You call me a Bean Counter? Guido, break this kid's fingers with an adding machine!") Powell 1111..22.. HHooww HHPP PPrriinntteerrss IImmpplleemmeenntt PPaaggee CCoouunntteerrss The following is from http://www.hp.com/cposupport/printers/support_doc/bpl02119.html HHPP LLaasseerrJJeett PPrriinntteerr FFaammiillyy -- PPaaggee CCoouunntt Description Of The Page Count Feature On HP LaserJet 4 Family Printers All HP LaserJet 4/5/6 family printers have a page count feature built into the firmware. However, this feature works differently depending on which HP LaserJet printer is being used. The following is a description of how the page count feature works for each printer within the HP LaserJet 4/5/6 printer families. HP LaserJet 4/4M printers HP LaserJet 4 Plus/4M Plus printers HP LaserJet 4P/4MP printers HP LaserJet 4Si/4Si MX printers HP LaserJet 4ML printers HP LaserJet 5P/5MP printers HP LaserJet 6P/6MP printers All of the above printers use the same method for keeping track of the number of copies. There are really two different page count values: Primary and Secondary values. Every time a page is printed, whether it is an internal job (such as a self-test) or a standard print job, the Secondary page count increases by one. This value is stored in standard RAM. Once the Secondary page count value reaches 10, the Primary page count will increase by 10. The Primary page count value is stored in a type of memory called NVRAM (Non-Volatile RAM). This is important, since NVRAM is not cleared when the printer is powered off. Standard RAM, on the other hand, is cleared when the printer is turned off or reset. Thus, the Primary page count only increases in increments of 10. Example You have a brand new HP LaserJet 6P printer and you print a self-test page. When you look on the test page for the Page Count value, you will see that it says 1. Next, you decide to print a two page letter and, after that, another self-test. The page count value now says 4. Internally, the printers Secondary page count (stored in RAM) has the value of 4 while the Primary page count (stored in NVRAM) still has the value of 0. Now, you turn the printer off, then back on, and print another self-test. The page count value again says 1 since the previous value of 4, stored in RAM, was cleared when the printer was powered off. Finally, print a ten page document and then turn the printer off. Upon turning the printer back on and printing out another self test, you see that the page count value is 11. Internally, the Secondary page count value is back at 1 while the Primary page count value (stored in NVRAM) is 10. Added together, you end up with the resulting value seen on the self-test page. HP LaserJet 4L/5L/6L Printers The reason that the page count method for the HP LaserJet 4L/5L/6L printers differ from that of the other printers is that the HP LaserJet 4L/5L/6L printers do not have any NVRAM available. Thus, no way exists for the printer to retain a page count value once the printer is powered off. The HP LaserJet 4L/5L/6L printers have only a single page count value that increases in increments of one until the printer is powered off. At that point, the page count value is reset and begins from 0 once again. 1111..33.. AAccccoouunnttiinngg PPrriinnttccaapp OOppttiioonnss The accounting facilities are controlled and enabled by the following entries in the printcap file. The default value is indicated. | | | | |Tag | Default Value | Purpose | |af | NULL | accounting file name | |as | "jobstart $H $n $P $k $b $t" | accounting info for job start | |ae | "jobend $H $n $P $k $b $t" | accounting info for job end | |accounting_server | NULL | | |achk | FALSE | | |la | TRUE | do accounting for 'local' printer | |ar | FALSE | do accounting for 'remote' transfers | 1111..44.. AAccccoouunnttiinngg FFiillee The most common method of accounting is to record the start and end times of a job and its size to the accounting file. A typical entry for the printcap defaults are shown below. jobstart -H'taco.astart.com' -n'root' -P'ps' -k'cfA938taco.astart.com' \ -b'1093' -t'Nov 5 19:39:59' start -p'12942' -k'cfA938taco.astart.com' -n'root' -h'taco.astart.com' -P'ps' \ -c'0' -F'o' -t'Sun Nov 5 19:39:25 1995' start -p'12944' -k'cfA938taco.astart.com' -n'root' -h'taco.astart.com' -P'ps' \ -c'0' -F'f' -t'Sun Nov 5 19:39:27 1995' end -p'12944' -k'cfA938taco.astart.com' -n'root' -h'taco.astart.com' -P'ps' \ -b'3' -c'0' -F'f' -t'Sun Nov 5 19:39:58 1995' end -p'12942' -k'cfA938taco.astart.com' -n'root' -h'taco.astart.com' -P'ps' \ -b'2' -c'0' -F'o' -t'Sun Nov 5 19:39:59 1995' jobend -H'taco.astart.com' -n'root' -P'ps' -k'cfA938taco.astart.com' \ -b'1093' -t'Nov 5 19:39:59' The jobstart and jobend lines are added by the LPD server, as specified by the as and ae printcap options; the -b (byte count) indicates the numbers of bytes in the job. The start and end lines are produced by the filters; the of filter has an -Fo, and the if filter a -Ff entry. The filters in the LPRng distribution produce the indicated output format by default. The -p value is the current value of a page counter device (if any), and the -b value indicates the total number of pages used. It should be clear that a simple AWK or Perl script will be able to process an accounting file and update accounting information for accounting purposes; the usual problems with truncation, time stamps, etc., are left as an exercise for the system administrator. Note that the accounting file must exist; LPRng will not create it (and also will not create the log file). This prevents accidentally growing log and accounting files. 1111..55.. RReemmoottee SSeerrvveerr AAccccoouunnttiinngg To accommodate even more aggressive and centralized accounting, a method to make a connection to a print server and send information to the server has been provided as well. If achk option is set, it is assumed that the af entry specifies a connection to server on a remote host. The lpd server will send the as string to the server, and then wait for a single line of text from the remote server. If the first word on the return line is accept or hold, the job will be either accepted for printing or held. Any other value will cause the job to be deleted. At the end of the job the ae string will be sent to the server. No response is expected. Example: :af=accounting.site.com%2300,tcp :achk :as=starting :ae=ending The port that the connection originates from will be in the range set by the configuration or printcap ``originate_port'' option. 1111..66.. UUssiinngg FFiilltteerrss FFoorr AAccccoouunnttiinngg Some sites have expressed interest in using a central accounting mechanism to check that users have permissions. This can be done by using the an alternative form of the as (accounting start) and ae (accounting end) printcap tags. If the as and ae are filter specifications, then a filter is invoked. If the as (accounting start) filter returns a non-zero exit status, then its value is used to handle the job as indicated by the ``Abnormal Termination'' codes for filters. At the end of the job the :ae: filter will be invoked in a similar manner, but its exit status is ignored. When using an accounting filter, the STDIN is attached (read/write) to the accounting file or remote host specified by the af printcap option, STDOUT to the output device, and STDERR to the log file. The filter program would be invoked with the default filter options. For example, here is a sample entry to check and update accounting printer :as=|/usr/local/lib/filters/accounting.pl start :ae=|/usr/local/lib/filters/accounting.pl end 1111..77.. AAccccoouunnttiinngg UUttiilliittyy aaccccoouunnttiinngg..ppll In order to provide a framework for doing using the outlined accounting methods, the LPRng distribution UTILS directory has a accounting.pl script. This script does the following. 1. It is assumed that the accounting filter is invoked with the following printcap entry. The start and end is used by the filter to determine at which point in the accounting process it is invoked. printer :as=|/usr/local/lib/filters/accounting.pl start :ae=|/usr/local/lib/filters/accounting.pl end 2. It maintains the accounting file as a set of entries in the following format: START [job identification] start -pnn ... ... end -pnn+pagecount ... END -ppagecount [job identification] 3. Each time the filter is invoked with the start tags, it will add a START record to the end of the accounting file. 4. When it is invoked with the end option, it will update the accounting file and add an END entry. 5. It will handle aborted jobs by looking for jobs with have a START entry and a following start line and assuming that they progressed to the point of starting print operations, i.e. - the printer page counter was accessed and reported. It will then look for the next START entry with a following start line, and assume that the pages between the two points were used by the aborted job. Administrators can use this script as a starting point for more advanced accounting. For example, rather than just recording the information, at the job start the script can query either a local database or a remote server to see if the user has permissions to access the printer. At the end of the job or when an END line is written to the accounting file, the local database or remote accounting server can be updated. 1122.. AAuutthheennttiiccaattiioonn aanndd EEnnccrryyppttiioonn One of the major problems in a print spooler system is providing privacy and authentication services for users. One method is to construct a specific set of protocols which will be used for providing the privacy or authentication; another is to provide a simple interface to a set of tools that will do the authentication and/or encryption. LPRng provides native support for the LPR extensions used by MIT and the Kerberos 4 implementation. In addition, it provides Kerberos 5 based authentication. LPRng also supports the use of the PGP (Pretty Good Privacy) program and can sign and optionally encrypt command and reponses between servers and clients. Finally, LPRng provide a general purpose interface allowing users to insert their own authentication methods, either at the program level or at the code level. 1122..11.. AAuutthheennttiiccaattiioonn A careful study of the authentication problem shows that it should be done during reception of commands and/or jobs from a remote user and/or spooler. At this time the following must be done: 1. The received command must be checked for consistency, and the remote user and host must be determined. 2. The remote user and host must be authenticated. 3. The command and/or spooling operation must be carried out. 4. The results must be returned to the remote system. 1122..22.. IIddeennttiiffiieerrss When a user logs into a system, they are assigned a user name and a corresponding UserID. This user name is used by the LPRng software when transferring jobs to identify the user. When we look into the problem of authentication, we will possibly have a more global user identification to deal with, the authentication identifier (AuthID). One way to deal with this problem is to give LPRng intimate knowledge of the UserID and AuthID relationship. While this is possible, it may be difficult to deal with in a simple and extensible manner. An alternate solution is to provide a mapping service, where the authentication procedure provides a map between the UserID and AuthID. 1122..33.. RRFFCC11117799 PPrroottooccooll EExxtteennssiioonnss The RFC1179 protocol specifies that a LPD server command sent on a connection has the form: \nnn[additional fields]\n \nnn is a one octet (byte) value with the following meaning: REQ_START 1 start printer REQ_RECV 2 transfer a printer job REQ_DSHORT 3 print short form of queue status REQ_DLONG 4 print long form of queue status REQ_REMOVE 5 remove jobs The LPRng system extends the protocol with the following additional types: REQ_CONTROL 6 do control operation REQ_BLOCK 7 transfer a block format print job REQ_SECURE 8 do operation with authentication REQ_VERBOSE 9 verbose status information REQ_LPSTAT 10 lpstat simulation The REQ_CONTROL allows a remote user to send LPC commands to the server. The REQ_BLOCK provides an alternate method to transfer a job. Rather than transferring the control and data files individually, this format transfers one file. The REQ_AUTH provides a mechanism for providing an authentication mechanism and is described in this document. 1122..44.. CClliieenntt OOppeerraattiioonnss ffoorr CClliieenntt TToo llppdd SSeerrvveerr AAuutthheennttiiccaattiioonn Options used: +o auth=_c_l_i_e_n_t _t_o _s_e_r_v_e_r _a_u_t_h_e_n_t_i_c_a_t_i_o_n _t_y_p_e +o auth_client_filter=_c_l_i_e_n_t _t_o _s_e_r_v_e_r _t_r_a_n_s_f_e_r _p_r_o_g_r_a_m +o auth_forward=_s_e_r_v_e_r _t_o _s_e_r_v_e_r _a_u_t_h_e_n_t_i_c_a_t_i_o_n _t_y_p_e +o auth_forward_filter=_s_e_r_v_e_r _t_o _s_e_r_v_e_r _t_r_a_n_s_f_e_r _p_r_o_g_r_a_m +o auth_forward_id=_S_e_r_v_e_r _i_d_e_n_t_i_f_i_c_a_t_i_o_n +o auth_receive_filter=_s_e_r_v_e_r _t_o _s_e_r_v_e_r _t_r_a_n_s_f_e_r _p_r_o_g_r_a_m +o auth_server_id=_s_e_r_v_e_r _i_d_e_n_t_i_f_i_c_a_t_i_o_n This section describes the general purpose interface used for client to server authentication. The LPRng client will generate a set of commands and place them in a file. The file is then encrypted and/or signed by the appropriate authentication method, and is transferred to the server. The server will then decrypt and/or check the signature, perform the requested actions, and in turn generate a file of status information. This file is encrypted and/or signed by the server, and sent to the client, where it is in turn decrypted and/or checked for correct signature. These activities are controlled by the following printcap or configuration options. 1. The auth option specifies the authentication type to be used for client to server transfers. For example, auth=pgp would specify PGP authentication, auth=kerberos5 would specify Kerberos 5 authentication, auth=kerberos4 would specify Kerberos 4 authentication, and auth=user would specify using user provided filters for authentication. 2. For client to server operations, the server id is the value of the auth_server_id option. 3. The auth_forward> option specifies the authentication type to be used for server to server transfers. 4. For server to server operations, the id of the originating server is specified by auth_server_id. and the remote server by auth_forward_id. 5. When doing client to server transfers, the originating user is determined by using the current UID of the program as the search value for getpwuid(). The LPRng client will open a connection to the server and send a command with the following format: \008printer C userid auth\n - for commands \008printer C userid auth jobsize\n - for print jobs Note that \008 is a one byte code indicating an authenticated transfer. Printer is the spool queue name, C in the character 'C' indicating a client request, userid is the login id of the user, auth is the the value of the auth option, and jobsize is the size of the job file to be printed. On reception of this command, the server will send a one byte success code. If an error is indicated by a non-zero response, additional error status may follow the non-zero success code byte. At the end of this information the connection will be terminated. The values used by LPRng are: ACK_SUCCESS 0 success ACK_STOP_Q 1 failed; no spooling to the remote queue ACK_RETRY 2 failed; retry later ACK_FAIL 3 failed; job rejected, no retry If the success code is zero, client will use the auth_client_filter to encrypt and/or sign a data file to be transferred to the server. The authentication program will have the following IO assignments: FD Options Purpose 0 R/W connection to remote host 1 W output for returned status 2 W errors Command line arguments: program -C -Pprinter -nuser -Aauth -Rauth_server_id -Ttempfile The tempfile will contain either a command line as would be transferred using the standard RFC1179 protocol, or a print job in block format. See ``RFC1179 Protocol'' for details. The client authenticator program will open and transfer the contents of tempfile to the server authenticator, using FD 0 and a format compatible with the underlying authentication mechanism. If the transfer fails the client authenticator will log error information on FD 2 and then exit with error code JFAIL. The server will send the client authentication program any error or logging information over the FD 0 connection, in a form appropriate to the authentication operation. The client authenticator will write this information to FD 1. If data transfer or authentication fails, the authenticator will write an error message to FD 2 and exit with error code JFAIL. If no error has occured the client authenticator will then exit with error code JSUCC. 1122..55.. SSeerrvveerr OOppeerraattiioonnss ffoorr CClliieenntt TToo llppdd SSeerrvveerr AAuutthheennttiiccaattiioonn Options used: +o auth_receive_filter=_S_e_r_v_e_r _(_l_p_d_) _a_u_t_h_e_n_t_i_c_a_t_i_o_n _p_r_o_g_r_a_m +o auth_server_id=_S_e_r_v_e_r _i_d_e_n_t_i_f_i_c_a_t_i_o_n When an authentication command arrives at the server, it has the following form: \008printer C userid auth\n - for commands \008printer C userid auth jobsize\n - for print jobs The server will attempt to find the printcap for the specified printer. For some operations this printer will be a dummy entry; this will simply cause the following operations to use the default information in the lpd configuration. If a print job is being performed and the spool queue does not exist, then the job will be rejected. A non-zero error code will be written to the connection and the operation will terminate. The auth value is used to set the AUTHTYPE permission checking value. If the AUTHTYPE is not built in, and the auth value does not match the printcap or configuration auth option value then authentication will fail. An error message will be logged to the server log file, and a non-zero error code and message will be written to the connection to the remote client program. Many authentication programs require that the users provide some form of key or identification. The auth_server_id option is used for this purpose. The server will start the server authenticator program and provide the following open file descriptors for it. The program will run as the same UID as the lpd server. If this is a print job transfer, the current directory will be the spool directory of the print queue. FD Options Purpose 0 R/W socket connection to remote host (R/W) 1 W pipe or file descriptor, for information for server 2 W error log 3 R pipe or file descriptor, for responses to client Command line arguments: program -S -PPRINTER -nUSER -aAUTHTYPE -Rauth_server_id -Ttempfile The PRINTER, USER, and AUTHTYPE, are obtained from the original command. The authentication filter will read the file transferred by the client authenticator, decrypt it, and place the decrypted values in the tempfile. It will then write a from_id string to FD 1, which will be read by the LPD server and used as the identification of the originating end of the connection. If the originating program is an LPRng client, then the from_id value will be the user identification for the authentication protocol; if the originating program is an LPRng server, this value will be the server identificatio for the authentication protocol. After writing this value, the transfer program will close FD 1. At this point the LPD server will use the contents of the tempfile to perform the various requested actions. If the transfer step or authentication fails, then the server authenticator will write an error message to FD 2 and exit with error code JFAIL. The lpd server will record the authentication information returned by the server in the AUTHUSER permissions key. The lpd server will perform the usual permissions checks, with the addition of the indicated permission keys and associated values. During this process, any error messages or logging information normally returned to client programs will be written to the authentication program FD 3. The lpd server will carry out either the commands or print job specified in the temporary file. During this process, any error messages or logging information normally returned to client programs will be written to the authentication program FD 3. At the end of the operations, the FD 3 file descriptor will be closed and the lpd server will wait for the authentication process to exit. The server authentication process will read input from FD 3 until the end of input, and then transfer the received information to the client side authenticator. It may use the tempfile to hold the information during the reading and transfer process. If the transfer of the logging information fails, then the authenticator process will exit with error code JFAIL, otherwise it will exit with error code JSUCC. 1122..66.. llppdd SSeerrvveerr ttoo SSeerrvveerr AAuutthheennttiiccaattiioonn Options used: +o auth_forward=_S_e_r_v_e_r _t_o _s_e_r_v_e_r _a_u_t_h_e_n_t_i_c_a_t_i_o_n _t_y_p_e +o auth_forward_id=_D_e_s_t_i_n_a_t_i_o_n _s_e_r_v_e_r _a_u_t_h_e_n_t_i_c_a_t_i_o_n _i_d The Server to Server authentication procedure is used by one server to forward jobs or commands to another server. It should be noted that this forwarding operation puts an implicit trust in the security of the client to server to server chain. The lpd server will perform an authenticated transfer to another server when it either needs to transfer a job to a remote printer or when it needs to propagate a lpq, lprm, or lprc operation. The procedure used to by the server to send commands and/or jobs is identical to that used by a client, with the minor modification that the server is identified as the originating endpoint of the connection, and the client authentication information is transferred in the file. When propagating a command, the server uses the authentication information provided for the remote user by the client to server authentication program. When propagating or forwarding a job, the server will use the authentication information stored in the job control or hold file. This information will be represented as AUTHUSER in the following discussion. The auth_forward option value specifies the type of authentication to be used to forward authentication, and the sending server uses the auth_server_id as its identification, and the auth_forward_id as the identification of the remote server. If there is no user authentication information, then a normal, non-authenticated transfer will be done. The auth_forward_filter will be used for the forwarding operation. The sending server takes the part of the client, and will transfer a job acting similar to a client. The initial information transfer from the sending server will have the format: \008printer F server_user authtype \n - for commands \008printer F server_user authtype controlfilename\n - for print jobs The sending server will invoke its authenticator with the arguments: auth_forward_filter -F -Pprinter -nserver_user -aauthtype \ -Rremote_user -Ttempfile The tempfile containing the job or command information to be sent will have the form: user_authentication_info\n \n That is, the user authentication information is place in the tempfile. The tempfile will be transferred to the remote server in the same fashion as for a user job. Any error or logging information returned will either be written to the lpd log file or to the previous lpd process in the transfer chain. On the destination server the same operations for receiving an authentication request from a client is performed. The AUTHUSER, AUTHFROM, and AUTHTYPE values will be the derived from the authentication request as for the client. The AUTHSAMEUSER will compare the remote client authentication information and the authentication information used to create the job. When the remote server receives the authentication request, it will carry out the same actions as for a client to server transfer, modified as follows: 1. The lpd server will remove the first line of the transferred file, which contains the user authentication information, and set AUTHUSER to this value. 2. Authentication is performed using the indicated values. 3. If authentication succeeds, then the command line or print job control file is processed in the normal manner. This might now add more permissions values to tags, but the authentication information will not be changed. 1122..77.. PPeerrmmiissssiioonn CChheecckkiinngg The following patterns and values can be used to check that a particular type of authentication has been used, and what the authenticated user information is. +o AUTH - authentication is used +o AUTHTYPE=globmatch This matches the type of authentication request. Built in values include kerberos4, kerberos5, and pgp. +o AUTHUSER=globmatch The originating auth_user_id value. +o AUTHFROM=globmatch When a command received from a server (i.e.- forwarded by a server), the value is the the forwarding servers authentication information, otherwise it is NULL. +o AUTHSAMEUSER The originating auth_user_id value is compared to the value used to create the job. If they are identical, the match succeeds. For example, to reject non-authenticated operations, the following line could be put in the permissions file. REJECT NOT AUTH To reject server forwarded authentication as well, we use the following. Note that the ? forces a value to be present. REJECT AUTH AUTHFROM=?* If a remote server has id information FFEDBEEFDEAF, then the following will accept only forwarded jobs from this server. Note that AUTHFROM will only match on authenticated transfers; FWDUSER will only match on forwarded transfers. ACCEPT AUTH AUTHFROM=FFEDBEEFDEAF REJECT AUTH REJECT NOT AUTH To allow only authenticated users to remove jobs you can use: ACCEPT AUTH SERVICE=R,M,L,P AUTHSAMEUSER REJECT AUTH REJECT NOT AUTH 1122..88.. UUssiinngg PPGGPP ffoorr AAuutthheennttiiccaattiioonn PGP is a well known encryption and authentication program. For more details see the web site http://www.pgp.net or the ftp site ftp://ftp.pgp.net. LPRng has greatly simplified the use of PGP for authentication by building in support as follows. The LPD server usually runs as user daemon, and opens files as daemon. The system administrator should establish a home directory for daemon, and use the PGP key generation facility to create a public and private key for the daemon user. By default, the PGP program puts the public and secret key rings in the $HOME/.pgp/ directory, and sets them to be readable only by the user. You should log in temporarily as daemon, run the pgp -kg command, and then disable logins for daemon. The user id chosen for the LPD server should be easily used to identify the server. For example, lpr@hostname, where hostname is the fully qualified domain name of the server is userful. The next step is to place the passphrase in a file that is only readable by daemon, say ~daemon/.pgp/serverkey, with owned by daemon, and with 600 permissions (read/write only by daemon). This is extremely important, as if any other users can read this file then security will be severely compromised. The next step is to distribute the lpr@hostname public key to all users of the LPRng server, and to place the public keys of LPRng users in the daemon public key ring. This can be done using: pgp -kxa userid destfile keyfile Example: > pgp -kxa lpr@astart /tmp/lprkey ~daemon/.pgp/pubring.pgp Key for user ID: lpr@astart 512-bit key, key ID BB261B89, created 1999/01/01 Transport armor file: /tmp/lprkey.asc Key extracted to file '/tmp/lprkey.asc'. User can add the lpr@astart key to their public key rings using: pgp -ka /tmp/lprkey.asc Finally, the administrator will need to add users public keys to the daemon users public key ring. This can most easily be done by copying all the keys (in ASCII text form) to a single file (/tmp/keyfile)and using: pgp -ka /tmp/keyfile ~daemon/.pgp/pubring.pgp 1122..88..11.. PPGGPP CCoonnffiigguurraattiioonn Options used: +o pgp_path=_p_a_t_h _t_o _P_G_P _p_r_o_g_r_a_m +o pgp_server_key=_p_a_t_h _t_o _s_e_r_v_e_r _p_a_s_s_p_h_r_a_s_e _f_i_l_e +o pgp_passphrase=_u_s_e_r _p_a_s_s_p_h_r_a_s_e _f_i_l_e _i_n _P_G_P_P_A_T_H _o_r _$_H_O_M_E_/_._p_g_p The pgp_path option is the path to the PGP program. The pgp_server_key is the path to the file containing the server passphrase. This file will be read by lpd to get the passphrase to unlock the server's keyring. The LPRng client software will check to see if the pgp_passphrase value (default clientkey) file in $PGPPATH, and if not present, then in $HOME/.pgp. By default, the pass_env option is pass_env=PGPPASS,PGPPATH,PGPPASSFD and will pass the values of the PGPPATH, PGPPASS, and PGPPASSFD environment variables. See below for a method to use these. Example printcap entry: pr: :lp=pr@wayoff :auth=pgp :auth_server_id=lpr@wayoff.com :pgp_path=/usr/local/bin/pgp :pgp_passphrase=.mypass One problem with using PGP is the need to have users input their passphrases. If the user is daring, then the pass phrase can be put in the file: ~/.pgp/clientkey . This file will be read by the LPRng client program the contents passed to PGP as the passphrase. This file MUST have 0400 permissions (read only by user) and MUST owned by the user. A more subtle solution is to use the PGPPASSFD environment variable facility. This causes PGP to read the passphrase from a file descriptor. If the user puts his passphrase in a file, say $(HOME)/.pgp/.hidden, then the following shell script can be used. #!/bin/sh # /usr/local/bin/pgplpr script - passphrase in $(HOME)/.pgp/.hidden # PGPASSFD=3 3<$(HOME)/.pgp/.hidden lpr "$@" 1122..88..22.. PPeerrmmiissssiioonnss If you wish to enforce the use of authentication, then you should modify the lpd.perms file. Here are some examples. # force authentication REJECT NO AUTH REJECT NO AUTHTYPE=pgp 1122..88..33.. CClliieenntt CCoonnffiigguurraattiioonn One problem with using PGP is the need to have users input their passphrases. If the user is daring, then the pass phrase can be put in the file: ~/.pgp/clientkey . This file will be read by the LPRng client program the contents passed to PGP as the passphrase. This file MUST have 0400 permissions (read only by user) and MUST owned by the user. A more subtle solution is to use the PGPPASSFD environment variable facility. This causes PGP to read the passphrase from a file descriptor. If the user puts his passphrase in a file, say $(HOME)/.pgp/.hidden, then the following shell script can be used. #!/bin/sh # /usr/local/bin/pgplpr script - passphrase in $(HOME)/.pgp/.hidden # PGPASSFD=3 3<$(HOME)/.pgp/.hidden lpr "$@" By using the -V (verbose) flag, users can see the results of the PGP interaction. 1122..99.. UUssiinngg KKeerrbbeerrooss 55 ffoorr AAuutthheennttiiccaattiioonn LPRng Kerberos 5 authentication is based on the Kerberos5-1.0.5 release as of March 28, 1999. This was obtained from MIT: 1. ftp to ATHENA-DIST.MIT.EDU (18.159.0.42), login anonymous, password your_email_address 2. Change into the directory '/pub/kerberos/ 3. Get the README files and look at the details of using FTP to get the distribution. Note that there are also patches available which you might want to use. Note that the distribution has only the most superficial documentation. There are no man pages for any of the support libraries, etc. etc. 1122..99..11.. KKeerrbbeerrooss IInnssttaallllaattiioonn PPrroocceedduurree 1. Get the Kerberos 5 distribution. 2. Compile and install the distribution. 3. Create the /etc/krb5.conf, /usr/local/var/krb5kdc/kdc.conf files using templates from the src/conf-files subdirectory. See the Installation notes and the System Administrators Guide. 4. Don't forget to create the /usr/local/var/krb5kdc/kdc.acl file; I did and it took me HOURS to figure out what was wrong... 5. Start up the KDC and KADMIN servers - you might want to put the following in your rc.local or equivalent file: if [ -f /etc/krb5.conf -a -f /usr/local/var/krb5kdc/kdc.conf ]; then echo -n ' krb5kdc '; /usr/local/sbin/krb5kdc; echo -n ' kadmind '; /usr/local/sbin/kadmind; fi 6. use kadmin (or kadmin.local) to create principals for your users. 7. Now you need to create principals for the lprng servers. I have been using lpr/hostname.REALM as a template- i.e. lpr/astart1.astart.com@ASTART.COM for an example. Do this for all the servers. You should use fully qualified domain names for the principals. 8. Now you need to extract the keytab for each of the servers: kadmin ... ktadd -k file_for_host lpr/hostname.REALM The 'file_for_host' contains the keytab information, which is the equivalent information for the server. 9. Copy the 'file_for_host' to the server (you might want to encrypt or use a secure transfer for this). You need to put this in /etc/lpd.keytab. Make sure that this file is readable only by user daemon, as it will try to read the file to get its server key. #> ls -l /etc/lpd.keytab -rw------- 1 daemon wheel 128 Jan 16 11:06 /etc/lpd.keytab 10. Modify (uncomment) the following entries in /etc/lpd.conf: auth=kerberos5 kerberos_keytab=/etc/lpd.keytab kerberos_service=lpr # optional - explicit prinipal name for server, used by clients #kerberos_server_principal=lpr/hostname@REALM # optional - forwarding to another server with authentication # kerberos_forward_principal=lpr/hostname@REALM The kerberos_keytab entry is the location of the keytab file; kerberos_service is the service that will be used to generate a server principal name. This is the lpr used in the above key generation operations. kerberos_life and kerberos_renew determine the lifetime and renewability of Kerberos tickets. The lifetime defaults to 10 hours, and the ticket will be refreshed when it expires if necessary. 11. You might like to check out the authentication using the sclient and sserver test programs. These link in the kerberos authentication and allow you to test it without all of LPD being involved. cd LPRng/src; make sserver sclient usage: sserver [-D] [-p port] [-s service] [-S keytab] file -D turns debugging on 1. opens TCP port 'port' (default 1234) 2. waits for a connection 3. when a connection comes in, uses 'service' to get the principal name of the server, and looks up the key in keytab file. 4. Goes through the kerberos authentication. 5. Copies the input from remote server to 'file' 6. exits. usage: sclient [-D] [-p port] [-s service] host file -D turns debugging on 1. opens a connection to port on host (i.e. - host%port) 2. does the authentication. You must have done kinit to get for your ticket to be valid. 3. sends the file to remote host. To test this, start up sserver on one host/window, then run sclient. The error messages are pretty straight forward, and when in doubt, look at the source code which has more than sufficient information. 1122..99..22.. TTeessttiinngg TTrraannssffeerrss Restart the server, and then try getting information using LPQ. You can turn on tracing at LPQ to see if authentication is being used and is working: lpq -Dnetwork,database If the lpq works, then try send a job and see if the transfer is successful. 1122..99..33.. EExxpplliicciitt SSeerrvveerr PPrriinncciippaall NNaammee If you are using printers in different domains, then you can put the explicit principal name of the server in the printcap file, using the server_principal entry. For example: lp_offsite :lp=printer@erehwon.org :auth=kerberos5 :auth_server_id=lpr/erehwon.org@BLUESKY.ORG 1122..1100.. UUssiinngg KKeerrbbeerrooss 44 ffoorr AAuutthheennttiiccaattiioonn LPRng has built-in support for the Project Athena extensions to the RFC1179 protocol. These provide an extremely simple authentication protocol using an initial credential exchange. After the initial exchange the usual RFC1179 protocol is used. To enable Kerberos 4 support, you must modify the LPRng/src/Makefile and recompile the LPRng code. You should be aware that this is not a supported extension, and is provided as a courtesy to MIT and Project Athena. 1133.. SSttaattuuss MMoonniittoorriinngg aanndd LLooggggiinngg Options used: +o stalled_time#_t_i_m_e _a_f_t_e_r _w_h_i_c_h _t_o _r_e_p_o_r_t _a _s_t_a_l_l_e_d _a_c_t_i_v_e _j_o_b The most commonly used tool for LPRng status is LPQ. However, the LPC command can be used, and you can also get real time logging of status to a remote host. 1133..11.. LLPPQQ ssttaattuuss rreeppoorrttiinngg The LPQ status display produced by LPRng has three formats. 1133..22.. LLPPQQ SShhoorrtt FFoorrmmaatt ((llppqq --ss)) This is one line per spool queue: % lpq -sa t1@astart110 (printing disabled) 1 job t2@astart110 (routed/bounce to t1@astart110.astart.com) 0 jobs t3@astart110 (forwarding to t3a@astart110.astart.com) t3a@astart110 (forwarding to t2@astart110.astart.com) t4@astart110 (subservers t5, t6) 0 jobs t5@astart110 (serving t4) 0 jobs t6@astart110 (serving t4) 0 jobs Note that the name of the printer/host is first, followed by optional status information, followed by the number of jobs. Only printcap entries with spool queues have a jobs word in the last position. The -a option forces status for all queues or the queues in the all printcap entry to be returned. The stalled_time (default 120 seconds) printcap option can be used to set a time after which active jobs will be reported as stalled. 1133..33.. LLPPQQ LLoonngg FFoorrmmaatt ((llppqq ddeeffaauulltt,, llppqq --ll,, llppqq --LL)) This is the default status display. It is a nicely formatted, extremely verbose format that is suitable for humble human interpretation. For example: % lpq -a Printer: t1@astart110 'Test Printer 1' (printing disabled) Queue: 1 printable job Server: no server active Status: finished operations at 09:44:00 Rank Owner/ID Class Job Files Size Time 1 papowell@astart110+202228663 A 10663 /tmp/hi 3 20:22:29 Printer: t2@astart110 'Test Printer 2' (routed/bounce to t1@astart110.astart.com) Queue: no printable jobs in queue Status: finished operations at 16:30:08 Printer: t3@astart110 (forwarding to t3a@astart110.astart.com) Printer: t3a@astart110 (forwarding to t2@astart110.astart.com) Printer: t4@astart110 (subservers t5, t6) Queue: no printable jobs in queue Status: finished operations at 09:44:06 Server Printer: t5@astart110 (serving t4) Queue: no printable jobs in queue Status: finished operations at 09:44:06 Server Printer: t6@astart110 (serving t4) Queue: no printable jobs in queue Status: finished operations at 09:10:00 The lpq -l (longer information) option causes more of the status information to be printed. You can use increasing numbers of lpq -l options ( lpq -ll also works) to get more status. Use lpq -L for the maximum amount of status information. 1133..44.. LLPPQQ VVeerrbboossee FFoorrmmaatt ((llppqq --vv)) This uses an extension to the RFC1179 protocol, and is supported only by LPRng. The amount of information displayed is the brutal, and in effect does a total database dump of the LPD. This has been developed in order to provide diagnostic and status information for databases that need to keep track of job progress through a spool queue. % lpq -v Printer: t1@astart110 Comment: Test Printer 1 Printing: no Spooling: yes Queue: 1 printable job Server: no server active Status: accounting at end 'papowell@astart110+094352860' at 09:44:00 Status: printing 'papowell@astart110+094352860', closing device at 09:44:00 Status: printing 'papowell@astart110+094352860', finished at 09:44:00 Status: subserver status 'JSUCC' for 'papowell@astart110+094352860' \ on attempt 1 at 09:44:00 Status: finished operations at 09:44:00 Job: papowell@astart110+202228663 status= 1 Job: papowell@astart110+202228663 CONTROL= - Hastart110.astart.com - Ppapowell - J/tmp/hi - CA - Lpapowell - Apapowell@astart110+202228663 - Qt1 - fdfA010663astart110.astart.com - N/tmp/hi - UdfA010663astart110.astart.com Job: papowell@astart110+202228663 HOLDFILE= - active 0 - done 0 - hold 0 - move 0 .... 1133..55.. llppcc ssttaattuuss The LPC status command is used to show the status of the queues currently being managed by the LPRng server. Note that this form of the command is supported only by LPRng, and is not backwards compatible with BSD LPR implementations. %lpc status all Printer Printing Spooling Jobs Server Slave Redirect Status/Debug lw4@astart4 enabled enabled 0 none none lw5@astart4 enabled enabled 0 none none The status display has a heading line and summary of the server status. 1133..66.. RReemmoottee LLooggggeerr OOppeerraattiioonn Several sites have wanted a way to provide central logging of job status and/or information. In order to do this, the following functionality is provided with LPRng. 1133..66..11.. LLooggggeerr NNeettwwoorrkk CCoommmmuunniiccaattiioonn Options used: +o logger_destination=_l_o_g_g_e_r _i_n_f_o_r_m_a_t_i_o_n _d_e_s_t_i_n_a_t_i_o_n +o logger_pathname=_p_a_t_h_n_a_m_e _o_f _t_e_m_p _f_i_l_e _f_o_r _l_o_g _i_n_f_o_r_m_a_t_i_o_n +o logger_max_size=_m_a_x _s_i_z_e _i_n _K _o_f _t_e_m_p _f_i_l_e _f_o_r _l_o_g _i_n_f_o_r_m_a_t_i_o_n +o logger_timeout=_t_i_m_e _b_e_t_w_e_e_n _c_o_n_n_e_c_t_i_o_n _a_t_t_e_m_p_t_s The printcap/configuration variable logger_destination specifies a destination in the standard host%port notation used by LPRng. Host is the destination host, and can be a name or IP address. Port is the port on the destination host. A TCP/IP connection is made to the indicated port. Log information is save in a temporary file specified by logger_path, and up to logger_max_size K bytes of data will be saved. If a connection cannot be made to the logger_destination, then every logger_timeout seconds a new connection attempt will be made. If logger_timeout is 0, then a connection attempt will be made every time new data arrives to be logged. 1133..66..22.. LLooggggeerr MMeessssaaggeess Log messages consist of a single line terminated with a newline (\n) character. Each log message reports a system event or status change of the LPD server. When the connection is first established, a complete dump of the status of the LPD server is sent. After this, only status update messages are sent. The remote monitor can force a status dump by simply closing and reopening the connection. 1133..66..33.. MMeessssaaggee FFoorrmmaatt Each message is encoded as a URI escaped string. That is, non- alphanumeric characters are encoded as the 3 character sequence %xx, where xx is the hexadecimal value of the character. The message has the format key=value, where key indicates the message type. For example: dump=host=astart4.astart.com%0aprinter=t1%0aprocess=1613%0aupdate_time=1999-03-2 3-20:32:17.148%0avalue=queue=holdall 0%25250aprinting_aborted=0x0%25250aprinting _disabled=0x0%25250aspooling_disabled=0x0%25250a%250a%0a The following keys are used: 1. dump A status dump of the current contents of a print queue. Each message has a set of headers and a value. For example, the decoded dump message from the previous section would be: host=astart4.astart.com printer=t1 process=1613 update_time=1999-03-23-20:32:17.148 value=queue=holdall 0%250aprinting_aborted=0x0%250aprinting_disabled=0x0%250aspo oling_disabled=0x0%250a%0a Each line consists of a key and a value. The host key indicates the host name, printer is the print queue, process is the process which generated the report or action, update_time is the time at which the report was generated, and value is the value of the report. The decoded value of the above report is: queue='holdall 0%0aprinting_aborted=0x0%0aprinting_disabled=0x0%0aspooling_dis abled=0x0%0a The queue key provides the current value of the queue control file. 1133..66..44.. DDuummpp MMeessssaaggeess Dump messages are generated at the start of operations, and consist of a list of queue status messages. 1133..66..55.. LLPPDD MMeessssaaggeess These are used to indicate LPD startup or change in operation. Decode: lpd=host=astart4.astart.com%0aprocess=1672%0aupdate_time=1999-03-23-20:5 1:10.507%0avalue=Starting%0a host=astart4.astart.com process=1672 update_time=1999-03-23-20:51:10.507 value=Starting lpd: 'Starting' 1133..66..66.. JJoobb SSttaattuuss MMeessssaaggeess -- UUPPDDAATTEE Update messages are used to report changes in the queue contents, such as job arrival. Decode: update=host=astart4.astart.com%0aidentifier=papowell@astart4+676%0anumbe ... host=astart4.astart.com identifier=papowell@astart4+676 number=676 printer=t1 process=1677 update_time=1999-03-23-20:51:17.197 value=bnrname=papowell%0acf_esc_image=Apapowell@astart4+676%250aCA%250aD1999-03- ... This update message reports the arrival of a new job at the queue. The value field reports the control file contents: cf_esc_image=Apapowell@astart4+676%0aCA%0aD1999-03-23-20:51:17.151%0aHastart4.as tart.com%0aJ/tmp/hi%0aLpapowell%0aPpapowell%0aQt1%0aN/tmp/hi%0afdfA676astart4.as tart.com%0aUdfA676astart4.astart.com%0a class=A date=1999-03-23-20:51:17.151 file_hostname=astart4.astart.com fromhost=astart4.astart.com held=0x0 hf_name=/var/tmp/LPD/t1/hfA676 hold_class=0x0 hold_time=0x0 identifier=papowell@astart4+676 job_time=0x36f86f45 jobname=/tmp/hi logname=papowell number=676 priority=A queuename=t1 size=3 transfername=cfA676astart4.astart.com update_time=1999-03-23-20:51:17.187 The update_time field in the section above is the time that the job information was last updated. The cf_esc_image value is the URL escaped control file information. 1133..66..77.. PPrriinntteerr SSttaattuuss MMeessssaaggeess -- PPRRSSTTAATTUUSS These messages report printing or other activity related to a job. Decode: prstatus=host=astart4.astart.com%0aidentifier=papowell@astart4+676%0anum ber=676%0aprinter=t1%0aprocess=1692%0aupdate_time=1999-03-23-21:02:04.855%0avalu e=finished 'papowell@astart4+676'%252c status 'JSUCC'%0a host=astart4.astart.com identifier=papowell@astart4+676 number=676 printer=t1 process=1692 update_time=1999-03-23-21:02:04.855 value=finished 'papowell@astart4+676'%2c status 'JSUCC' PRSTATUS: 'finished 'papowell@astart4+676', status 'JSUCC'' 1133..77.. LLPPRR --mmhhoosstt%%ppoorrtt aanndd uusseerr llooggggiinngg ssuuppppoorrtt The lpr -m option is used to request that lpd send mail to the user when a job has completed. LPRng extends this to allow mail addresses of the form host[%port][/(TCP|UPD)] to request that logging information be sent to the user as well. The administrator should be aware that this is a possible security loophole, and that the allow_user_logging flag must be enabled to allow this operation. 1144.. RRFFCC 11117799 -- LLiinnee PPrriinntteerr DDaaeemmoonn PPrroottooccooll RFC1179 can be obtained from the LPRng distribution, in the LPRng_DOC/rfc1179 directory, or from one of many sites which mirror the RFCs. This RFC is an _i_n_f_o_r_m_a_t_i_o_n_a_l RFC, which means that the information in it is meant as a guide to users, and not as a fixed standard. In addition, the RFC tried to document the behavior of the BSD LPD print server, and left out many details dealing with error recover, error messages, extensions to the protocol, etc. In this section, I will try to explain what RFC1179 specifies as a protocol, and many of the problems encountered in trying to use it. 1144..11.. PPoorrttss aanndd CCoonnnneeccttiioonnss Options used: +o lpd_port=_P_o_r_t _f_o_r _L_P_D _t_o _a_c_c_e_p_t _c_o_n_n_e_c_t_i_o_n +o originate_port=_P_o_r_t_s _t_o _o_r_i_g_i_n_a_t_e _c_o_n_n_e_c_t_i_o_n_s _o_n +o reuse_addr _S_e_t _S_O___R_E_U_S_E_A_D_D_R _f_l_a_g _o_n _c_o_n_n_e_c_t_i_o_n +o retry_econnrefused _R_e_t_r_y _o_n _c_o_n_n_e_c_t _E_C_O_N_N_R_E_F_U_S_E_D _e_r_r_o_r +o retry_nolink _R_e_t_r_y _o_n _d_e_v_i_c_e _o_p_e_n _o_r _c_o_n_n_e_c_t_i_o_n _f_f_a_i_l_u_r_e +o socket_linger# _L_i_n_g_e_r _t_i_m_e _f_o_r _s_o_c_k_e_t_s RFC1179 requires that the lpd server listen for TCP/IP connections on port 515. This port is registered with the Internet Naming Authority, and the /etc/services file or TCP/IP services database usually has an entry: printer 515/tcp spooler # line printer spooler RFC1179 explicitly states that all connections to port 515 must originate from ports 721-731. The reason for this restriction is due to the UNIX concept of _r_e_s_e_r_v_e_d and _p_r_i_v_i_l_e_g_e_d ports. By convention, ports in the range 1-1023 can only bboouunndd by processes whose Effective User ID (EUID) is 0 (root). This, ordinary users could not originate a connection from the reserved or privileged port range. In a UNIX environment, this means that the user programs lpr, lprm, lpq, and lpc would have to be SETUID root. As experience has shown, for security purposes, the fewer programs that need to have privileged status, the better. LPRng uses the lpd_port=printer configuration option to set the actual port to be use. By default, this is port 515, but can be set to other values. The restriction of originating ports to 721-731 causes another set of problems. Part of the TCP/IP protocol is concerned with avoiding communications problems resulting from the arrival of old or _s_t_a_l_e packets. When a connection between sourcehost, sourceport and desthost, destport is made, a set of sequence numbers is established and used for sending and acknowledgement of data. When the connection terminates, the TCP/IP protocol restricts the establishment of a new connection between sourcehost, sourceport and desthost, destport for a period long enough for all _s_t_a_l_e packets to be removed from the system. This is approximately 10 minutes long. In order to simplify assignments of ports, timing out connections, and other matters, many TCP/IP packages do keep track of explicit connections _o_r_i_g_i_n_a_t_i_n_g from a port, but simply prevent the port from being reused for either origination or reception of a connection. They do, however, keep track of the active connections ttoo a port, and perform timeouts on these. This is usually much simpler to implement, as it can be done with a list attached to the port. This implementation method creates some problems when a large number of connections must be originated from a relatively small number of port numbers. Observe what happens when host 1 tries to send a large number of jobs to a server 2. The following connections are established and terminated: host 1, port 721 and host 2, port 515 host 1, port 722 and host 2, port 515 host 1, port 723 and host 2, port 515 host 1, port 724 and host 2, port 515 host 1, port 725 and host 2, port 515 host 1, port 726 and host 2, port 515 host 1, port 727 and host 2, port 515 host 1, port 728 and host 2, port 515 host 1, port 729 and host 2, port 515 host 1, port 730 and host 2, port 515 host 1, port 731 and host 2, port 515 Now according to the RFC1179 rules and the TCP/IP protocol, we will have to wait until one of these connections terminates before we can make another. On the originating system, if the TCP/IP implementation does timeouts on the originating port, we will have to wait for the timeout to elapse before we can make a new connection. Unfortunately, there is no way to find out what the status of the port is, so we will have to try them each in turn until we get a successful connection. The LPRng code has tried to provide several methods to deal with these problems. Firstly, the originate_port=512 1023 option specifies the range of ports used to originate connections when the software is running either as ROOT or SETUID root. By strict RFC1179 rules, this should be originate_port=721 731, but it turns out that most BSD LPD based implementations only check for a _r_e_s_e_r_v_e_d originating port. By using 512 ports we get a greatly reduced rate of errors due to lack of ports due to pending timeouts. However, on some systems which are acting as servers for a large number of printers even increasing this port range is insufficient, and steps need to be taken use the originating port numbers more efficiently. The Berkeley TCP/IP implementation getsockopt() and setsockopt() allows the user to manipulate some of the underlying timeouts and options of the TCP/IP network. When a TCP/IP connection is established, the setsockopt() facility can be used to set the SO_REUSEADDR flag on the connection. This flag effectively sets the timeout value on the ports and connections to 0, allowing immediate reuse of the ports. When done on an originating end of a connection, this will allow the originating port number to be reused immediately. It would appear that by setting SO_REUSEADDR on the originating end that we have solved our problems. However, unless the destination end of the connection sets its SO_REUSEADDR flag on the connection, it will still do a timeout. Thus when we try to make a connection from a port that was active within a short period of time to the same host, then it will reject the connection until the timeout is over. The reuse_addr flag (default off) forces the LPRng software to set the SO_REUSEADDR flag on originating connections. As indicated, this will allow ports to be reused immediately for outgoing connections, rather than waiting for a timeout. While the reuse_addr flag usually allows us to reuse ports, there is still the problem of dealing with connections failing due to the remote site rejecting the connection due to a pending timeout from a previous connection. A careful study of the original BSD TCP/IP network code and of some others indicates that when a connection fails due to a pending timeout, an ECONNREFUSED error code is returned to a connect() system call. If this happens and we suspect that the remote site is rejecting the connection due to a timeout problem, then we should retry making the connection but from a new port, and continue retrying until all possible ports are used. The retry_econnrefused (default on) flag is used to specify that we retry connections in this manner. When this is set, a connection refused error causes the connection to be retried using a new port. This will be repeated until all available ports have been tried. When printing a job and the lpd server connection to a remote site or device open fails, the retry_nolink (default on) will cause the attempt to be retried indefinately. The combination of retry_econnrefused and retry_nolink will provide robust connection attempts to remote systems. While the above problems cause difficulties when making connections, there are also problems when terminating connections. After closing a socket, the TCP/IP software will try to flush any pending data to the destination. Unfortunately, on some systems it will only do this while the process is active. This has caused problems on systems which terminate a process it has received an abnormal (signal caused) termination. The setsockopt() SO_LINGER option allows the user to specify that when a socket is closed normally, that the process should block until pending data is flushed or for the socket_linger period. If socket_linger is 0, then no SO_LINGER operation is done. In summary, if you experience problems with connection failures due to port exhaustion, first try setting the reuse_port flag, and you should see a reduction. Check to ensure that the retry_econnrefused and retry_nolink flags are set, and the error code in the log and status files. If the failures continue, then the problem is caused by the remote end having timeout limitations and there is little you can do except to set a very long connect_retry interval, say connect_retry=120 (2 minutes). 1144..22.. PPrroottooccooll RReeqquueessttss aanndd RReepplliieess Options used: +o remote_support=_R_e_m_o_t_e _o_p_e_r_a_t_i_o_n_s _s_u_p_p_o_r_t_e_d After a connection has been established, a request can be sent to the lpd server. The request consists of a single octet indicating the request type, followed by the printer (or print queue) name, followed by a set of options for the request, followed by a LF (line feed) character. \NNNprinter[ options]\n NNN Operation | | | | | |NNN | RFC1179 | Operation | program | |1 | yes | start print | lpc | |2 | yes | transfer a printer job | lpr | |3 | yes | print short form of queue status | lpq | |4 | yes | print long form of queue status | lpq | |5 | yes | remove jobs | lprm | |6 | LPRng | do control operation | lpc | |7 | LPRng | transfer a block format print job | lpr | |8 | LPRng | secure command transfer | lpc | |9 | LPRng | verbose status information | lpq | After the request has been sent, then a reply will be returned. In general the reply has the following form: \000\n Success \NNN\n Failure (NNN is error code) text\n Text or status information As can be seen, this protocol is extremely simple, but there are a set of problems due to the loosely written language of RFC1179. 1. Firstly, while RFC1179 sets limits on the lengths of commands, it does not strictly set limits on the characters set used in the commands. This can result in problems when trying to print status information, headers on banners, and other details. 2. The original RFC1179 protocol did not provide any way to do remote control of queues or LPD servers. This has been added to the protocol. As a side effect, if you try to use lpc to control a non-LPRng printer, it will not work. 3. You can specify that a network printer is non-LPRng by using the remote_support=RQVMC option and specify the operations supported by the printer. The letters R, Q, V, M, and C stand for lpr, lpq, lpq -v (verbose), verbose lpq, lprm, and lpc operations respectively, and indicate that these are supported. If remote_support does not allow a particular operation, then the LPRng software will not send a corresponding request to the printer. For example, remote_support=R would restrict operations to spooling jobs only, and the LPRng software would not query the printer for status. 1144..33.. JJoobb TTrraannssffeerr Options used: +o longnumber _L_o_n_g _j_o_b _n_u_m_b_e_r _(_6 _d_i_g_i_t_s_) +o send_data_first _S_e_n_d _d_a_t_a _f_i_l_e_s _f_i_r_s_t +o use_shorthost _U_s_e _s_h_o_r_t _h_o_s_t_n_a_m_e A job transfer operation starts with a job transfer request, followed by several file transfer operations. At the end of the file transfers, the connection should be closed. A file transfer request has the form: | | | | | |Command | Purpose | | | |\001\n | abort | | | |\002nnnn cfname | control file transfer | | | |\003nnnn dfname | data file transfer | | | The abort operation is used to terminate job transfer and indicate that the job should not be processed for printing. The connection will be closed and the partly transferred job will be discarded. The control file and data file transfer commands have a length (in bytes) of the file and the name of the file to be transferred. When the command is received, the server will reply with a status line: | | | | | |Status | Purpose | | | |\000 | Accepted, proceed | | | |\nnn | Rejected with error code | | | The reply is only a single octet. Some defective implementations of RFC1179 send a LF after the octet, which makes life very difficult. LPRng makes an effort to detect these non-conforming RFC1179 systems and will accept jobs from them. However, it will not send jobs to them. If LPRng sends a reject code, as an extension to RFC1179 it also sends an error message. Note that the values for error codes are not defined, nor are their causes. LPRng uses the following values for error codes, which appear to be compatible with many, but not all, of the BSD LPD based systems: | | | | | |Code | Error | | | |\000 | Accepted, proceed | | | |\001 | Queue not accepting jobs | | | |\002 | Queue temporarily full, retry later | | | |\003 | Bad job format, do not retry | | | When the sender gets the reply indicating success, it sends the nnnn bytes of the control or data file, followed by a \000 octet. The receiver will then reply as above; a single \000 octet indicating success. The above procedure is carried out until all data files and the control file of a job are transferred. RFC1179 is silent on the following issues: 1. When sending a job, do you send the control file first, followed by the data file(s), or the data files first? 2. When sending multiple jobs, can you send them on a single connection, or do you have to establish a new connection for each job? LPRng will _a_c_c_e_p_t jobs whether they are sent control or data files first. By default, it sends the control file first, followed by the data file. If the destination system requires that the data files be sent first, the send_data_first printcap option can be used to force data files to be sent first. RFC1179 states that: The name of the control file ... should start with ASCII "cfA", followed by a three digit job number, followed by the host name which has constructed the control file. The _s_h_o_u_l_d in this wording indicates that this is simply a guideline, and that other formats are possible. Some of the major problems with this format are as follows: 1. The restriction to 3 digits means that at most 1000 jobs can be in a queue. Strangely, some systems generate far more than 1000 jobs a day, and need to archive them on a regular basis. The longnumber option will allow LPRng to use a 6 digit job number for files in the print queue. 2. The host name format is not specified. Some implementations consider that this is the short host name, while others think it is the fully qualified domain name (FQDN). LPRng, by default, will use the FQDN host name. However, the use_shorthost option will force it to use short host names in control and data files. 3. The cfA control file name was modified to allow the job priority to be used as the A letter of the control file. By default, this is A (lowest, i.e. cfA) and but can range to Z (highest, i.e. cfZ). All known spoolers except LPRng seem to ignore the actual value of the letter. 1144..44.. DDaattaa FFiillee TTrraannssffeerr As discussed, a data file is transferred using the command below. | | | | | |Command | Purpose | | | |\003nnnn dfname | data file transfer | | | From RFC1179: The data file may contain any 8 bit values at all. The total number of bytes in the stream may be sent as the first operand, otherwise the field should be cleared to 0. The name of the data file should start with ASCII "dfA". This should be followed by a three digit job number. The job number should be followed by the host name which has con- structed the data file. Interpretation of the contents of the data file is determined by the contents of the corre- sponding control file. There are several surprises in RFC1179. 1. Apparently a job should only consist of a single data file. This is a severe limitation, and in fact the BSD LPR and other print spoolers process jobs with multiple data files. By convention, these data files have names of the form dfA, dfB, ... dfZ, dfa, dfz. 2. The RFC does not specify that the control file and data file job numbers must be identical. Most implementations follow this convention, which simplifies life tremendously. 3. The RFC does not specify that the control file and data file job host names must be identical. Most implementations follow this convention, which simplifies life tremendously. 4. A zero length data file does not cause a data transfer to take place. LPRng modifies this action to be slightly different. When a zero length data file transfer is indicated, all of the input until the connection is closed is used as the contents of the data file. When 'piping' into the lpr program, this can be very useful as it eliminates the need to create temporary files on the senders host. The lpr -k option for details. Note that some print spoolers do not use this interpretation, and this option should be used carefully. 1144..55.. CCoonnttrrooll FFiillee CCoonntteennttss The control file consists of a set of lines which either provide printing information or specify data files to be printed. The information lines start with upper case letters or digits, while the data files lines start with lower case letters. Here is a sample control file: Hastart4.astart.com J(stdin) CA Lpapowell Apapowell@astart4+955 Ppapowell fdfA955astart4.astart.com N(stdin) UdfA955astart4.astart.com The following are the letters and their meanings in the control file. The A (Identifier) line was introduced to record a unique system wide job identifier for LPRng submitted jobs. This is basically formed from the user name, job number, and host at the time of submission. For example: papowell@astart4+955 is job number 995 submitted by papowell from host astart4. The C (Class) line is set by the lpr -C class option, and the value can be used to control printing. For example, the lpc class zone command would restrict job printing to only jobs with class zone. The H (hostname), P (username), and J (jobname) fields are used to identify the host and user which sent the job, and to provide information to be displayed by lpq when reporting job status. The L (print banner page) field is one that has caused many problems for users. RFC1179 indicates that its presence causes the banner page to be printed, and its absense suppresses banner pages. The lpr -h option suppresses putting this line into the control file. Usually the L field is a duplicate of the P field. The M (mail information) field supplies a mail address for LPRng to send mail to when a job is completed. See ``LPR -m and user logging'' for more details. | | | | | |X | RFC1179 | Meaning | | |A | LPRng | Identifier for job | | |C | RFC1179 | Class for banner page | | |H | RFC1179 | Host name | | |I | RFC1179 | Indent Printing | | |J | RFC1179 | Job name for banner page | | |L | RFC1179 | Print banner page | | |M | RFC1179 | Mail When Printed | | |N | RFC1179 | Name of source file | | |P | RFC1179 | User identification | | |Q | LPRng | Queue name | | |R | LPRng | Accounting info | | |S | RFC1179 | Symbolic link data | | |T | RFC1179 | Title for pr | | |U | RFC1179 | Unlink data file | | |W | RFC1179 | Width of output | | |Z | LPRng | Filter options | | |1 | RFC1179 | troff R font | | |2 | RFC1179 | troff I font | | |3 | RFC1179 | troff B font | | |4 | RFC1179 | troff S font | | |c | RFC1179 | Plot CIF file | | |d | RFC1179 | Print DVI file | | |f | RFC1179 | Print formatted file | | |g | RFC1179 | Plot file | | |k | RFC1179 | Reserved for use by Kerberized LPR clients and servers. | | |l | RFC1179 | Print file leaving control characters | | |n | RFC1179 | Print ditroff output file | | |o | RFC1179 | Print Postscript output file | | |p | RFC1179 | Print file with 'pr' format | | |t | RFC1179 | Print troff output file | | |v | RFC1179 | Print raster file | | |z | RFC1179 | Reserved for future use with the Palladium print system. | | The N (file name) field is usually provided to identify the file name corresponding to the data file. This can be used to print names on page separators, etc. LPRng largely ignores this line. The I (indent) and W (width) fields are supposed to specify a page indent and width for printing. These fields are passed to filters if they are present. The Q (queue name) field is an LPRng extension, and contains the name of the print queue the job was originally sent to. See ``qq printcap option'' for details. The R (accounting info) field was added by LPRng to allow a specified account to be billed for job printing. The lpr -Rname option can be used to specify the accounting name. The S (symbolic link) and U (unlink after printing) lines were used by the original BSD LPD print system to control how it passed files to the print server. LPRng ignores these lines. In fact, it will remove S lines and force the U lines to refer only to job data files. This closes a nasty security loophole on non-LPRng print spoolers. The T (pr job title) is used with the lpr -p operation to supply a banner to the pr program. The Z (filter options) value is specified with lpr -Zoption and is passed to the data file filters during the printing operation. See ``Filters'' for details on how the this is used during the printing process. All of the lower case letters are reserved for format specifications for data files. In the control file, these are followed by the name of the data file to which they correspond. While in principle different data files in the control file can have different formats, this has not been implemented in any known spooling system. See ``Filters'' for details on how the data file formats are used during the printing process. 1144..66.. LLPPQQ RReeqquueessttss The RFC1179 protocol specifies that lpq print status requests can be sent to the lpd server. The lpq requests have the format: \003printer [id]* \n short \004printer [id]* \n long \009printer [id]* \n LPRng extension- verbose The lpd print server will then return queue status and close the data connection. RFC1179 does not state in any manner what the format of the queue status should be. Thus, implementors have been free to augment or change the status as they like. Even the BSD LPR status format has been changed from different versions. See ``Status Monitoring and Logging'' for information on the formats returned. The id values are used to select the jobs to be displayed. LPRng displays any job whose ID, hostname, or user name information from the control file A, H, or P fields match any of the id values. Note that since there is no identification of the information requestor, then restriction of information is almost impossible. 1144..77.. LLPPRRMM RReeqquueessttss The RFC1179 protocol specifies that lprm job removal requests can be sent to the lpd server. The lpq requests have the format: \005printer user [id]* \n The lpd print server will search the specified print queue and remove any job whose ID, hostname, or user name information from the control file A, H, or P fields match any of the id values and for which the user has permission to perform a removal operation. See the ``/etc/lpd.perms'' file for details on permissions. Most RFC1179 compatible spoolers use the user information in the request as the name of the user which spooled the job. However, in a network environment this is extremely easy to fabricate, and is at best a weak type of authentication. 1144..88.. LLPPCC RReeqquueessttss LPRng has extended the RFC1179 protocol to allow queue and printer control commands to be sent to the LPD server. The format of these commands are: \006printer user key [options] The following commands are supported. | | | | | |Command | Operation | | | | active [printer[@host]] | check to see if server accepting connections | | | | abort (printer[@host] | all) | terminate server process printing job | | | | disable (printer[@host] | all) | disable queueing | | | | debug (printer[@host] | all) debugparms | set debug level for printer | | | | enable (printer[@host] | all) | enable queueing | | | | hold (printer[@host] | all) (name[@host] | job | all)* | hold job | | | | holdall (printer[@host] | all) | hold all jobs on | | | | kill (printer[@host] | all) | stop and restart server | | | | lpd [printer[@host]] | get LPD PID for server | | | | lpq (printer[@host] | all) (name[@host] | job | all)* | invoke LPQ | | | | lprm (printer[@host] | all) (name[@host]|host|job| all)* | invoke LPRM | | | | move printer (user|jobid)* target | move jobs to new queue | | | | noholdall (printer[@host] | all) | hold all jobs off | | | | printcap (printer[@host] | all) | report printcap values | | | | quit | exit LPC | | | | redirect (printer[@host] | all) (printer@host | off )* | redirect jobs | | | | release (printer[@host] | all) (name[@host] | job | all)* | release job | | | | reread [printer[@host]] | LPD reread database information | | | | start (printer[@host] | all) | start printing | | | | status (printer[@host] | all) | status of printers | | | | stop (printer[@host] | all) | stop printing | | | | topq (printer[@host] | all) (name[@host] | job | all)* | reorder job | | | | defaultq | default queue for LPD server | | | | local (printer | all) | client printcap and configuration information | | | | server (printer | all) | server printcap and configuration information | | | Many of these commands support extremely specialized operations for print queue management, However, the following are the most commonly used and are supported by the BSD LPD print spooling system as well: +o start, stop, enable, disable Start and stop will start and stop printing for a specified queue. Enable and disable enable and disable sending and/or accepting jobs for the queue. +o abort, kill Abort will cause the process doing the actual job printing to be terminated. Kill does an abort, and then restarts the printing process. These commands are used to restart a queue printing after some disaster. +o topq Places selected jobs at the top of the print queue. +o status Shows a status display of the print spools on the server. The following commands are extensions to the basic set provided by the BSD LPD system. +o lpq, lprm Invokes the lpq or lprm program from lpc. Useful when in the interactive mode. +o hold, holdall, release The hold command will cause the selected jobs to be held until released. The holdall jobs sets all jobs submitted to the queue to be held until released. The release command releases jobs for printing. If a job has had an error and is in the error state, the release command will cause it to be reprinted. +o move, redirect The move command will move selected jobs to the specified spool queue. The redirect command sends all jobs submitted to the queue to be sent to the specified queue. +o active, lpd, reread The active command will connect to the server for the printer. This is used to check to see if non-LPRng print servers are active. The lpd command will connect to the server and get the process id (PID) of the lpd server. The reread command causes a SIGHUP signal to be sent to the lpd process, causing it to reread the /etc/lpd.conf, /etc/printcap, or /etc/lpd.perms files. This is usually done when some important configuration information has been modified and the administrator wants to have the server use the new information. +o debug This is a desperation facility for developers that allows dynamic enabling of debug information generation. Not normally used in general operation. +o local, server These commands will print out the configuration information in the local /etc/lpd.conf file, as well as the printcap information for the specified printers; local prints what the LPRng clients (lpr, lpq, ...) would use while server prints what the LPRng server (lpd) would use if running on this host. This is an extremely useful diagnostic tool for administrators. Not normally used in general operation. 1144..99.. BBlloocckk JJoobb TTrraannssffeerr Options used: +o send_block_format _T_r_a_n_s_f_e_r _j_o_b _a_s _a _b_l_o_c_k In normal job transfer operations, the sender and receiver have a handshake interaction in order to transfer a print job. Each file is sent individually. The send_block_format option forces a Block Job Transfer operation. This causes the sender to transfer a single file containing all the job printing information, including control file and data files. The transfer command line has the form: \006printer user@host size\n The receiver will return any acknowledgement of a single 0 octet, and then the size bytes of the job will be transferred by the sender. At the end of the transfer a single 0 octet is added, and the receiver will indicate success by returning a single 0 octet. Any other value returned by the receiver indicates an error condition. The file transferred by the sender is simply the command lines that it would have normally sent for job transfer, followed by the control or data file values. 1144..1100.. AAuutthheennttiiccaatteedd TTrraannssffeerr RFC1179 does not provide any authentication or encryption mechanism for the transfer of jobs or commands to the lpd print server. The Authenticated Transfer operation was added to allow an encrypted or authenticated transfer of print jobs or commands. Since there are various restrictions on the incorporation of authentication facilities into programs, LPRng supports authentication by providing a simple interface to encryption programs. The idea is that when authentication is required when sending a job, LPRng will generate a block transfer job as described for the ``Block Transfer operation,'' and then invoke a set of programs to encryt and transfer the file, and encrypt and transfer the returned status. Similarly, when sending a command, the command information will be placed in a file and the encrypted file will be transferred. This technique means that the programs and support to do encryption are external to LPRng, and can use any type of method that they choose to implement the secure and/or authenticated transfer. See ``Authentication and Encryption'' for details on the authentication interface. 1155.. AAcckknnoowwlleeddggeemmeennttss I'd like to thank the proof-readers from the LPRng mailing list, in particular: Lars Anderson, Bertrand Decouty, Horst Fickenscher, Philip Griffith, Gordon Haverland, John Perkins, Richard S. Shuford, James H. Young and the ones I forgot. Finally, Patrick would like to thank all of the LPRng users who so relentlessly tried the incredible number of permutations and combinations of printers and software, and made requests for _j_u_s_t _o_n_e _m_o_r_e _f_e_a_t_u_r_e.