=head1	NAME

prqd - Print quota enforcement daemon

=head1	SYNOPSYS

  prqd

=head1	DESCRIPTION

Prqd can be used in conjunction with LPRng to enforce print quota by
limiting the number of pages users can print on a queue.

Limits can be set in general (for all users), based on UNIX group
membership and individually. Additionally users can have a personal
print account.

This is useful in public computer labs in schools and universities.
All students are allowed to print a limited number of pages per
semester as required in the courses. The limit expires at the end of
each semester. Additionally users can have a personal print account for
private purposes. Print accounts do not expire.

Printing is allowed if at least one of the following conditions is true:

=over	4

=item	The user has not yet reached the limit or

=item	there is a positive number of pages in the personal print account.

=back

=head1	OPTIONS

The program does not use any options.

=head1	RETURN VALUE

The program returns 0 on success, positive values on errors.

=head1	DIAGNOSTICS

The program writes log messages to ${prefix}/var/log/prqd/prqd.log,
typically /usr/local/var/log/prqd/prqd.log.

=head1	FILES

=head2	Configuration file structure

When entering service mode the program reads the configuration file
${prefix}/etc/prqd/prqd.conf, typically /usr/local/etc/prqd/prqd.conf.

The configuration file consists of a list of sections, typically there
is one options section and a number of class and printer sections.
Each section is introduced by the section header in square brackets.
The section contents is a number of lines, each line contains
one key/value pair. Key and value are separated by ``=''.

The options section sets general options for the daemon itself.

A class section contains limit information for a class of printers
(a group of printers).

The printer sections assign a class to each printers. Optionally
each printer can be given a number of aliases. Aliases must match
the aliases specified in the printcap file.

=head2	The options section

The options section is started by the B<[options]> section header.
The following lines are allowed:

=over	4

=item	B<database> = I<type:name>

specifies the type (``ndbm'', ``gdbm'' or ``bdb'') of the database
backend and the name of the database file.

=item	B<socket> = I<name>

specifies the file name for the UNIX domain socket used for communication
between prqd and the clients (prqdcl, prqdadm and prqdinfo).

=item	B<socket timeout> = I<timeout>

specifies the timeout for socket operations in seconds.

=item	B<user information directory> = I<name>

specifies the directory name for user information files.

=item	B<run as user> = I<uname>

specifies the user name used to run prqd in service mode.

=item	B<run as group> = I<gname>

specifies the group name used to run prqd in service mode.

=back

=head2	Class sections

Class sections are started by B<[class> I<name>B<]> section headers.

The following lines can occur in class sections:

=over	4

=item	B<limit> = I<limit-value>

specifies a limit. The I<limit-value> can have the following structure:

=over	8

=item	B<default:>I<limit>

specifies the general limit.

=item	B<group:>I<gname>B<:>I<limit>

specifies the limit for a UNIX user group.

=item	B<user:>I<user>B<:>I<limit>

specifies the limit for one user.

=back

The I<limit> can be either a number, or ``deny'' or ``unlimited''.

=item	B<deny action> = I<action>

specifies the action to take when printing is denied. The action
can be either ``remove'' or ``hold''.

=item	B<write user information> = I<boolean>

specifies whether or not to write user information files for this
printer class.

=back

=head2	Printer section

A printer section is started by the B<[printer >I<name>B<]> section
header. It can contain the following lines:

=over	4

=item	B<class> = I<name>

assigns a printer class to that printer.

=item	B<alias> = I<name>

assigns an alias to the printer.

=back

=head1	EXAMPLES

=head2	Example situation

A university faculty has two PC labs equipped with networked printers
lp1 and lp2. Students can print up to 200 pages per semesters on both
printers in summary. Faculty stuff is allowed to print unlimited.

In a centralized equipment root there is a color laser printer and a copier.
Faculty staff has unlimited access to both printers, students are not
allowed to use these printers.

The print server host running LPRng is named ps. We decide to run prqd
on the same host, so we can use the pipe mechanism for communication
between LPRng and prqdcl (this is more secure than using network
connections).

Here is an excerpt from /etc/hosts:

  192.168.101.33	lp1
  192.168.101.34	lp2
  192.168.101.35	lpcolor
  192.168.101.36	copier
  192.168.101.65	ps

The copier can be used both manually and as a networked printer. So we
can not do reliable accounting (a user can start a copy job manually
on the machine before fsnmp succeeded to retrieve the page count).
But we want to use prqd to allow access to copier for staff members
and to deny access for students.

=head2	Example printcap file

  lp1
	:client
	:force_localhost@
	:lp=lp1@ps.my-domain.com
  lp2
	:client
	:force_localhost@
	:lp=lp2@ps.my-domain.com
  lpcolor
	:client
	:force_localhost@
	:lp=lpcolor@ps.my-domain.com
  copier
	:client
	:force_localhost@
	:lp=copier@ps.my-domain.com
  lp1
	:server:oh=ps.my-domain.com
	:sd=/var/spool/lprng/lp1
	:sh
	:mx#0
	:lp=/dev/null
	:af=|/usr/local/bin/prqdcl
	:achk
	:filter=/usr/local/libexec/filters/fsnmp
  lp2
	:server:oh=ps.my-domain.com
	:sd=/var/spool/lprng/lp2
	:sh
	:mx#0
	:lp=/dev/null
	:af=|/usr/local/bin/prqdcl
	:achk
	:filter=/usr/local/libexec/filters/fsnmp
  lpcolor
	:server:oh=ps.my-domain.com
	:sd=/var/spool/lprng/lpcolor
	:sh
	:mx#0
	:lp=/dev/null
	:af=|/usr/local/bin/prqdcl
	:achk
	:filter=/usr/local/libexec/filters/fsnmp
  copier
	:server:oh=ps.my-domain.com
	:sd=/var/spool/lprng/copier
	:sh
	:mx#0
	:lp=192.168.101.36%9100
	:af=|/usr/local/bin/prqdcl
	:achk

=head2	Example fsnmp.conf file

  [lp1]
  lp				=	192.168.101.33%9100
  snmp version			=	1
  snmp community		=	public
  ctrl-d at end			=	yes
  shutdown data socket		=	no
  minimum pagecount time	=	30
  data transfer port range	=	9100 9110
  accounting destination	=	|/usr/local/bin/prqdcl

  [lp2]
  lp				=	192.168.101.34%9100
  snmp version			=	1
  snmp community		=	public
  ctrl-d at end			=	yes
  shutdown data socket		=	no
  minimum pagecount time	=	30
  data transfer port range	=	9100 9110
  accounting destination	=	|/usr/local/bin/prqdcl

  [lpcolor]
  lp				=	192.168.101.35%9100
  snmp version			=	1
  snmp community		=	public
  ctrl-d at end			=	yes
  shutdown data socket		=	no
  minimum pagecount time	=	30
  data transfer port range	=	9100 9110
  accounting destination	=	|/usr/local/bin/prqdcl

=head2	Example prqd.conf file

  [options]
  database			=	ndbm:/var/prqd/prqd
  socket			=	/var/run/prqd/prqd.sock
  socket timeout		=	1.5
  user information directory	=	/opt/printing
  run as group			=	daemon
  run as user			=	prqdu

  [class staff-pr]
  limit				=	default:deny
  limit				=	group:staff:unlimited
  limit				=	user:root:unlimited

  [class stud-pr]
  limit				=	default:200
  limit				=	group:staff:unlimited
  limit				=	user:root:unlimited

  [printer lp1]
  class				=	stud-pr

  [printer lp2]
  class				=	stud-pr

  [printer lpcolor]
  class				=	staff-pr

  [printer copier]
  class				=	staff-pr

=head2	Example explaination

In the printcap file we tell LPRng not to send print job data directly
to the printers, instead data is passed to the fsnmp print filter.
LPRng must not open a network connection to the printer, for some
printers this would cause problems when attempting to retrieve the
printer status (Some printers change the status to ``busy'' immediately
after a network connection is established. Fsnmp waits for the printer
to become ``ready'' before asking for the page count.).
So LPRng opens the /dev/null device, not a network connection to the
printer.

Both LPRng and fsnmp pass accounting information to the prqdcl
program. When LPRng starts a print job it sends a ``jobstart''
request to prqdcl and waits for a response. The response
``ACCEPT'', ``HOLD'' or ``REMOVE'' decides whether or not the print
job data is transferred to the printer, kept in the queue or removed.

The printers have built-in support for SNMP version 1. The SNMP
community is ``public''.
The filter ensures that the last byte sent to the printer is a
CTRL-D.

Fsnmp connects to port 9100 on the printers. The source port
must be in the range from 9100 to 9110.
Our printers do not support a clean shutdown of TCP/IP
connections.

If the page count did not change during a print job, fsnmp checks 
for 30 seconds whether or not the printer changes the state from
``ready'' to ``busy'' again.

Prqd uses an NDBM database stored in /var/prqd. The file name prqd will
result in a prqd.dir and a prqd.pag file in that directory for NDBM databases.

User information files are crated in /opt/printing. This directory must
be writable for users prqdu from group daemon because prqd changes
the current user and group before entering service mode.

We have two printer classes:

=over	4

=item	staff-pr

The printers usable by staff members only. Access to printers in this
class is denied generally, but members of the UNIX user group ``staff''
are allowed to print unlimited, user root too.

=item	stud-pr

The printers for use by students in the PC labs. The general limit
is 200 pages. Members of the ``staff'' group and the user ``root''
can print unlimited.

=back

=head1	SEE ALSO

fsnmp(1), LPRng, http://dktools.sourceforge.net/prqd.html

=head1	AUTHOR

Dipl.-Ing. Dirk Krause

=head1	COPYRIGHT AND LICENSE

Copyright (c) 2007-2008, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above
   copyright notice, this list of conditions and the
   following disclaimer.

 * Redistributions in binary form must reproduce the above
   copyright notice, this list of conditions and the following
   disclaimer in the documentation and/or other materials
   provided with the distribution.

 * Neither the name of the Dirk Krause nor the names of
   contributors may be used to endorse or promote products
   derived from this software without specific prior written
   permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

