Next Previous Contents

14. Permissions and Authentication

The contents of the /etc/lpd.perms file are used to control access to the lpd server facilities. The model used for permission granting is similar to packet filters. An incoming request is tested against a list of rules, and the first match found determines the action to be taken. The action is either ACCEPT or the request is granted, or REJECT and the request is denied. You can also establish a default action.

The following is a sample 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

Each line of the permissions file is a rule. 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 REMOTEUSER=john,bill succeeds only if the REMOTEUSER value is defined and is not john or bill.

Each entry in a rule is a keyword which has is assigned a value or list of values followed by an optional set of patterns that are matched against these values. The following table is a summary of the available keywords.


Keyword
Match
DEFAULTdefault result
SERVICEChecking lpC, lpR, lprM, lpQ, and Printing
USERP (logname) field name in print job control file.
REMOTEUSERuser name in request from remote host.
HOSTDNS and IP address information for the H (host) field name in print job control file
REMOTEHOSTDNS and IP address information for the connection from the remote host making the request
IPAlias for HOST
REMOTEIPAlias for REMOTEHOST
REMOTEPORTOriginating TCP/IP port for the connection from the remote host making the request
SAMEUSERUSER and REMOTEUSER matches
SAMEHOSTHOST and REMOTEHOST matches
SERVERrequest originates on lpd server
FORWARDdestination of job is not host
REMOTEGROUPREMOTEUSER is in the specified group or netgroup in the lpd server group database.
GROUPUSER is in the specified group or netgroup in the lpd server group database.
LPCLPC command in the LPC request.
CONTROLLINEmatch a line in control file
AUTHauthentication type
AUTHUSERauthenticated user
AUTHFROMauthenticated forwarder
AUTHJOBauthenticated job in queue

14.1 Permission Checking Algorithm

The lpd server uses the following algorithm to do permission checks.

  1. Each line of the permissions file is a lists of tests (patterns) and a permission value that is used if all of the tests (patterns) on the line are successful. A DEFAULT line sets the default result if all lines fail.
  2. Each line is executed in sequence until a match is found. The first matching line terminates the permission checking and the corresponding permission value is used.
  3. Each keyword has a value (or set of values) that are matched against a set of patterns. If the keyword does not have a value (or the null value) then the match will fail. Initially, all the keywords have a null value.
  4. When a connection is received by the lpd server, REMOTEHOST and REMOTEPORT are set to the the IP addresses and hostnames, and the TCP/IP port of the host originating the IP address respectively. REMOTEIP and IFHP are aliases for REMOTEPORT and PORT is an alias for REMOTEPORT. Thes are provided for backwards compatibility with older versions of LPRng. For example, a request originating from 10.0.0.2, port 1011 would set REMOTEIP to 10.0.0.2 and PORT to 1011.
  5. The REMOTEHOST value is set to the result of doing a reverse DNS lookup on the REMOTEIP address. This value is the list of names and ip addresses in standard IP notation (nnn.nnn.nnn.nnn) that are returned by the lookup. If the DNS lookup fails then the REMOTEHOST value is set to the REMOTEIP value. For example, lookup of 10.0.0.2 would result in the names h2.private and patrick.private, and the only IP address assigned to it was 10.0.0.2. The REMOTEHOST value would then be the list h2.private,patrick.private,10.0.0.2.
  6. The SERVICE value is set to X and then the permissions database is scanned for a matching entry. The result is the permission value of the first matching line or the default permission. If the result is REJECT then the connection is closed.
  7. Next, a single line is read from the connection. This line contains the request type, the print queue name, and depending on the request type an optional user name and options. The SERVICE value is set to R, Q, M, and C, for a lpR, lpQ, lprM, and lpc request respectively and PRINTER to the print queue name.
  8. If the request is for an lpc operation, the LPC value is set to the name of the operation. For example, and lpc lpd operation
  9. If the request contains a user name then REMOTEUSER is assigned the user name.
  10. If the request originates from the lpd server as determined by the connection arriving from the localhost address or an address assigned to one of the network interfaces for this host then the SERVER value is set to true (or matches).
  11. If the request is for an authenticated transfer, (see Authentication and Encryption), then the authentication procedures are carried out. After they have been performed, the AUTH value is set to true, AUTHTYPE is set to the name of the authentication method, AUTHUSER to the authenticated identifier of the originator of the request, and AUTHFROM to the authenticated identifier of the originator of the connection.
  12. Other matching keywords such as REMOTEGROUP use values set at this time. These are discussed in the next section.
  13. The permission database is rescanned, this time to see if there is permission to operate on the specified spool queue. The permission database is first checked to see if the requesting user has control (SERVICE=C) permission. If they do, then they can permform any operation on the spool queue. The scan is then repeated for the actual request.
  14. If there is no permission to perform the operation then an error code and messages is returned on the requesting connection.
  15. If the operation is for a spool queue or server, no other permissions checking is done. This includes the lpq command, and most of the lpc commands control queue operations.
  16. If the operation is for for individual jobs in a spool queue, then the queue is scanned and job information is extracted for each job in the queue. The USER value is set to the job control file P line. The value of the H line in the control file is used to perform a DNS lookup, and the HOST value is set to the results of this lookup. IP is an alias for HOST, and is retained for backwards compatibility.
  17. The SAMEUSER value is set to true (or match) if the REMOTEUSER value is identical to the USER value. Similarly, SAMEHOST is set to true if the REMOTEHOST value matches the HOST value. See the following sections for other keywords such as GROUP.
  18. The permission checking is done for each individual job in a spool queue, and if it succeeds the action is carried out on the job.

These checks are applied on the arrival of a job from an external connection. Unfortunately, there are a set of print spooler implementations that do not handle job rejection due to lack of permissions. These printers will continually and repeatedly attempt to send a job for which there is no printing permission until the job is removed by administrative action. To accommodate these printers, we must accept jobs for printing and then dispose of them. This is done by using the SERVICE=P (printing) checks.

  1. When a print spool is active and is printing or forwarding jobs, before it processes a job it will read the job control file and set the USER and HOST values as discussed in the previous sections. It will also set the AUTH, AUTHUSER, and AUTHJOB values as well, if the job was spooled by using an authenticated method.
  2. The permissions database will be scanned and the resulting permission determined. Note that the values of the REMOTE keys are undefined, and tests using them will have unpredicitible effects.
  3. If the job does not have permission to be printed, it will normally be removed from the spool queue.

While this model is very simple it can handle a wide range of situations. However, it is really based on the simple trust that users will not impersonate other users or hosts. If this is not the case, then more elaborate proceedures based on encryption and authentication are called for.

There is a problem with permissions checking for lpq (SERVICE=Q) requests. Since the user name is not passed as part of the request, it is impossible to use the REMOTEUSER clause to restrict lpq operations.

The SERVICE=R and SERVICE=P facilities are provided to handle problems with print spoolers that do not recognize a lack of permission error code, and will indefinately retry sending a job to the lpd server. If this is the case, then the SERVICE=R clause can be used to accept jobs, and then the SERVICE=P clause will cause the lpd server to remove of the job when it is scheduled for printing.

14.2 Rule Matching Procedures

[not] key                                 assigned value
[not] key=pattern                         substring match
[not] key=pattern1,pattern2,pattern3,...  glob and exact
[not] 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. assigned value. The keyword has an assigned value which is true (match) or false (no match). Examples are SAMEHOST and SERVER.
  2. substring match. The indicated entry is present as a substring in the pattern.
  3. 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.
  4. 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.

  5. 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.
  6. Same IP Address Match. This compares two lists of IP addresses; a match is found when there is one or more common addresses.

DEFAULT

DEFAULT ACCEPT
DEFAULT REJECT

The DEFAULT rule specifies the default if no rule matches. Normally, there is one DEFAULT entry in a permissions file.

Example:

DEFAULT ACCEPT

SERVICE

Match type: substring

The SERVICE key is based on the type of request.


Key
Request
CLPC Control Request
MLPRM Removal Request
PPrinting
QLPQ Status Request
RLPR Job Transfer
XConnection Request

Each of the above codes corresponds either directly to the user command, or a set of subcommands.

If you have an LPC request, you can add an LPC=xxx clause to refine the permissions checking to allow or disallow lpc commands such as lpc status, printcap, active, .

Example:

# control only from root on server
ACCEPT SERVICE=C SERVER USER=root
REJECT SERVICE=C
# accept all others
ACCEPT SERVICE=*

USER

Match type: GLOB

The USER information is taken from the P (person or logname) information in the print job control file.

Example:

# we allow jobs to be spooled
ACCEPT SERVICE=R
# now we do the checking at print time
ACCEPT SERVICE=P USER=root
REJECT SERVICE=P

REMOTEUSER

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.

Example:

ACCEPT SERVICE=C REMOTEUSER=root,papowell,admin SERVER
ACCEPT SERVICE=C LPC=status,lpd REMOTEUSER=admin
REJECT SERVICE=C

HOST

Match type: GLOB

The H (host) information in the print job control file is used to do a DNS lookup, and the resulting list of names and addresses is used for matching purposes.

Example:

# we allow jobs to be spooled
ACCEPT SERVICE=R
# now we do the checking at print time
# allow from our private subnet
ACCEPT SERVICE=P HOST=10.0.0.0/8,*.othernet.com
REJECT SERVICE=P

REMOTEHOST

Match type: GLOB

The REMOTEHOST information is obtained by doing a reverse IP name lookup on the remote host IP address and the resulting list of names and addresses is used for matching purposes. If there is no FQDN available, then the IP address in text form will be used.

Example:

# allow from our private subnet
ACCEPT SERVICE=R REMOTEHOST=10.0.0.0/8,*.othernet.com
REJECT SERVICE=R

REMOTEPORT

Match type: integer range

The REMOTEPORT value is the originating port of the TCP/IP connection. The match succeeds if it is in the specified range.

Example:

# require connections to originate from priviledged port
ACCEPT SERVICE=X REMOTEPORT=1-1023
REJECT SERVICE=X

PORT

Alias for REMOTEPORT.

IP

Alias for HOST.

REMOTEIP

Alias for REMOTEHOST.

LPC

Match type: GLOB

The requested lpc command. This allows the following permissions line to be used:

Example:

#allow remoteuser admin on server to use LPC topq and hold
ACCEPT SERVICE=C SERVER REMOTEUSER=root
ACCEPT LPC=topq,hold SERVER REMOTEUSER=papowell
REJECT SERVICE=C

SAMEUSER

Match type: exact string match

Both the REMOTEUSER and USER information must be present and identical.

Example:

# LPC users can do anything
ACCEPT SERVICE=C SERVER REMOTEUSER=root
REJECT SERVICE=C
# allow users who sent jobs from the same host to remove them
ACCEPT SERVICE=M SAMEUSER SAMEHOST
REJECT SERVICE=M

SAMEHOST

Match type: Same IP Address

The REMOTEHOST and HOST address lists are checked; if there is a common value the match succeeds.

Example:

# allow root on the same host as user
# to remove files
ACCEPT SERVICE=M SAMEHOST REMOTEUSER=root
REJECT SERVICE=M

SERVER

Match type: Matching 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().

Example:

# allow root on the server full LPC permissions
ACCEPT SERVICE=C SERVER REMOTEUSER=root
REJECT SERVICE=C

FORWARD

Match type: Address Match

The list of REMOTEHOST and HOST addresses must not have a common entry. This is usually the case when a remote lpd server is forwarding jobs to the lpd server.

Example:

# do not accept forwarded jobs or requests
REJECT SERVICE=* FORWARD

GROUP

Match type: modified GLOB

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 has the form @name, then a check to see if the user is in the named netgroup is done.

Example:

ACCEPT SERVICE=P GROUP=admin,@netgroup
REJECT SERVICE=P

REMOTEGROUP

The same rules as for GROUP, but using the REMOTEUSER value.

Example:

ACCEPT SERVICE=R REMOTEGROUP=admin,@netgroup
REJECT SERVICE=R

CONTROLLINE

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.

AUTH

Match type: value

If the current transfer or the transfer used to send a job was authenticated, then AUTH is true or matches.

Example:

# reject all non-authenticated transfers
REJECT NOT AUTH

AUTHTYPE

Match type: glob

If the current transfer or the transfer used to send a job was authenticated, then AUTHTYPE is set to the name of the authentication method.

Example:

# require kerberos, pgp, or md5 authentication
REJECT NOT AUTHTYPE=kerberos*,pgp,md5

AUTHUSER

Match type: GLOB

The AUTHUSER rule will check to see if the authenticated user identification matches the pattern.

Example:

ACCEPT SERVICE=C AUTHTYPE=kerberos* AUTHUSER=admin@ASTART.COM

IFIP

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 interface that accepted the network connection, 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 canonical host name. Some systems which use the Domain Name Server (DNS) system may add the canonical system name as an alias.

This entry is deprecated and may not be supported in future releases.

14.3 Permission File Location

Options used:

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

The lpd server will write either a blank line for connection (SERVICE=X) and global lpc permissions (SERVICE=C and LPC=reread,lpd,default) or the name of the spool queue to the get_perms STDIN, and expects to read permission information from its STDOUT. If the filter method is used, it should always return the complete set of connection (X) and control (C service values.

14.4 Example Permission File

# allow root on server to control jobs
ACCEPT SERVICE=C SERVER REMOTEUSER=root
ACCEPT SERVICE=C LPC=lpd
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. We also allow anybody to use the lpc lpd command. 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.

14.5 Complex Permission Checking

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,*.murphy.com would reject all requests from hosts which did not have a DNS entry ending in astart.com or murphy.com.

14.6 More Examples

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

14.7 Authentication

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 MIT Kerberos 4 extensions and Kerberos 5 authentication.

LPRng has native support for the PGP (Pretty Good Privacy) program and can sign and optionally encrypt command and responses between servers and clients. Due to legal restrictions, an external PGP program must be used for this purpose.

A simple MD5 hash based authentication scheme is also provided as an example to illustrate how new or different authentication methods can be adddd.

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.

14.8 Authentication

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.

14.9 Identifiers

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 is 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.

14.10 RFC1179 Protocol Extensions

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

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.

14.11 Authentication Operations

Options used:

A client (lpr, lpc, etc to lpd server authenticated transfer proceeds as follows. If an authenticated transfer is specified by the auth=protocol entry in the printcap or configuration information, the client sends a request for an authenticated transfer to the server.

Part of the authentication request is the authentication type. If authentication type XX is requested the server will examine the information in the printcap and configuration entries for an XX_id value. If this value is present then the server supports authentication of this type. Further permission checks are carried out and finally the server will accept or reject the authentication request. If the request is accepted the server returns a postive acknowlegement (single 0 byte) to the requester, otherwise it returns a nonzero value and an error message.

If the request is accepted then an authentication specific protocol exchange is carried out between client and server. The commands and/or data files are encrypted and/or signed and transferred to the server. The protocol specific software on the server will then decrypt and/or check signatures, perform the requested actions, and in turn generate a status information. The status information is encrypted and/or signed by the server and sent to the client, where the client decrypts and/or checked for correct signature.

A lpd server to lpd server authenticated transfer proceeds as follows. If an authenticated transfer is specified by the auth_forward=protocol entry in the printcap or configuration information, the originating server sends a request for an authenticated transfer to the destination server. The originating server plays the part of the client and performs the same set of actions.

The following printcap or user level information needs to be provided for an authenticated exchange.

  1. The auth option specifies the authentication type to be used for client to server transfers. For example, auth=kerberos or auth=kerberos5 or would specify Kerberos 5 authentication, auth=kerberos4 would specify Kerberos 4 authentication, auth=pgp would specify PGP authentication, auth=md5 would specify MD5 authentication, etc. The special form auth@ specifies no authentication.
  2. The auth_forward option specifies the authentication type to be used for server to server transfers. For example, auth_forward=kerberos5 would specify Kerberos 5 authentication, etc. The special form auth@ specifies no authentication.
  3. The authenticated transfer request sent to a server has one of the following forms, depending on the orginator:
    \008printer C user_id authtype \n     - for commands (lpq, lpc, etc.)
    \008printer C user_id authtype size\n - for print jobs (lpr)
    \008printer F server_id authtype \n     - forwarded commands (lpq, lpc, etc.)
    \008printer F server_id authtype size\n - forwarded print jobs (lpr)
    

    The single character with the \008 value signals that this is an authentication request the printer is the name of a print queue, and the C (client) or F indicates that the request is from a client program or is a forwarded request from a server. The user_id or server_id field is an identifier supplied by the originator and is dicussed below. If the size value is present then the request is for a job transfer and this value represents the job size. It is used to determine if there is sufficient space in the spool queue for the job.

  4. The user_id or server_id fields in the authentication request are obtained as follows. If the request originates from a client, then the user_id is the user name of the originator obtained from password information. If the request originates from a server, then the server_id is the printcap or configuration xx_id=server_id value, where xx is the value of the auth_forward=xx entry.
  5. When the authenticated transfer request is received, the destination will either return a single zero byte, or a non-zero byte value followed by additional refusal information. A refusal terminates the protocol exchange.
  6. Further exchanges are then determined by the authentication protocol specific requirements.
  7. Once the initial exchanges have been completed a user file and/or command will be transferred to the destination server.
  8. An authentication protcol specific AUTHFROM and AUTHUSER strings will be supplied to the lpd server for purposes of permission checking.
  9. The lpd server then carries out the requested operation, and will write error and status information into a file.
  10. After the requested activity has finished, protocol specific module transfer the status information in the file to the requesting system and terminate the protocol exchange.

14.12 Permission Checking

When an authenticated transfer has been performed, the following permission information will be provided.

For example, to reject non-authenticated operations, the following line could be put in the permissions file.

REJECT NOT AUTH

If a remote server has id information FFEDBEEFDEAF, then the following will accept only forwarded jobs from this server.

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

14.13 PGP Authentication Support

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.

Printcap Configuration

Options used:

Example printcap entry:

pr:
    :lp=pr@wayoff
    :auth=pgp
    :pgp_id=lpr@wayoff.com
    :pgp_path=/usr/local/bin/pgp
pr:server
    :lp=pr@faroff
    :auth_forward=pgp
    :pgp_id=lpr@wayoff.com
    :pgp_path=/usr/bin/pgp
    :pgp_forward_id=lpr@faroff.com

The pgp_path value is the path to the PGP program. The progam must be executable by all users.

The pgp_id value is the id used by PGP to look extract keys from key rings. When doing a client to server transfer this will be supplied as the id to be used for the destination, and the user's public keyring will be checked for a key corresponding to this id. When a request arrives at the server, the server will use this value as the id of a key in its private key ring. Finally, when a server is forwarding a request to a remote server, it will use this value as the id of the key in its private key ring to be used to sign or encode the destination information.

The pgp_forward_id value is used by the lpd server as the id to use to find a key for the destination.

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.

User Files and Environment Variables

Options used:

One problem with using PGP is the need to have users input their passphrases. The following methods can be used.

14.14 Using Kerberos 5 for Authentication

LPRng Kerberos 5 authentication is based on the Kerberos5-1.1.1 release as of December 28, 1999. This was obtained from MIT from the http://web.mit.edu/kerberos/www/ Website.

The following sections briefly describes how to set up and test the Kerberos software and then how to configure LPRng to use Kerberos.

LPRng Configuration

By default, LPRng will search for the krb5.h file and the krb5 libraries. If it finds these, then Kerberos authentication will be included. If it also finds the krb.h file then MIT Kerberos 4 compatibility will also be enabled.

Kerberos Installation Procedure

  1. Get the Kerberos 5 distribution.
  2. Compile and install the distribution.
  3. Create the /etc/krb5.conf and /usr/local/var/krb5kdc/kdc.conf, files using templates from the files in the Kerberos distribution's src/config-files directory. See the Installation notes and the System Administrators Guide for details.
  4. Start up the KDC and KADMIN servers - you might want to put the following in your rc.local or equivalent system startup files:
    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
    
  5. Use kadmin (or kadmin.local) to create principals for your users.
  6. Use kadmin (or kadmin.local) to create principals for the lpd servers. I have been using lpr/hostname.REALM as a template- i.e. lpr/astart1.astart.com@ASTART.COM for an example. You should use fully qualified domain names for the principals. Since it will never be used by an individual, you do not have to give it a password.
    Example:
    
    kadmin ...
    addprinc -randkey lpr/wayoff.astart.com@ASTART.COM
    
  7. Extract the keytab for each server:
    kadmin ...
    ktadd -k keytab  lpr/hostname.REALM
    
    Example:
    ktadd -k /tmp/lpr.wayoff.astart.com  lpr/wayoff.astart.com@ASTART.COM
    
  8. The keytab file contains the keytab information, which is the equivalent information for the server.
  9. Copy each keytab file to the appropriate server (you might want to encrypt or use a secure transfer for this). Put it in the /etc/lpd.keytab file on the server. This file should have 0400 permissions and owned by daemon or the user that lpd will run as.
    #> ls -l /etc/lpd.keytab
    -rw-------  1 daemon  wheel  128 Jan 16 11:06 /etc/lpd.keytab
    
  10. If you want to have MIT Kerberos4 printing compatibility, then you will need to set up Kerberos 4 servertabs instead of Kerberos 5 keytabs. Assuming that you have put the Kerberos 5 keytab in /etc/lpd.keytab, then you extract the Kerberos 4 srvtab version of the Kerberos 5 keytab using the following commands. You must put the key in the /etc/srvtab file in order to be compatible with the Kerberos 4 support.
    %> su
    #> ktuil
    rkt /etc/lpd.keytab
    wst /etc/srvtab
    

LPRng Configuration

The LPRng software needs to be configured so that it can find the Kerberos libraries and include files. By default, the include files are installed in /usr/local/include and the libraries in /usr/local/lib. Use the following steps to configure LPRng so that it uses these directories during configuration and installation:

cd .../LPRng
rm -f config.cache
CPPFLAGS="-I/usr/local/include -I/usr/include/kerberosIV" \
  LDFLAGS="-L/usr/local/lib -L/usr/lib/kerberosIV" \
  ./configure
make clean all
su
make install

Printcap Entries

Options used:

Example printcap entry:

pr:
    :lp=pr@wayoff
    :auth=kerberos5
    :kerberos_id=lpr/wayoff.astart.com@ASTART.COM
pr:server
    :lp=pr@faroff.private
    :auth_forward=kerberos5
    :kerberos_id=lpr@wayoff.astart.com@ASTART.COM
    :kerberos_forward_id=lpr/faroff.astart.com@ASTART.COM

OR If you want to use Kerberos 4 authentication to the server
pr:
    :lp=pr@wayoff
    :auth=kerberos4
    :kerberos_id=lpr/wayoff.astart.com@ASTART.COM
# support both Kerberos 4 and 5 on server
pr:server
    :lp=pr@faroff.private
    :auth_forward=kerberos5
    :kerberos_id=lpr@wayoff.astart.com@ASTART.COM
    :kerberos_forward_id=lpr/faroff.astart.com@ASTART.COM
    :kerberos_keytab=/etc/lpd.keytab

The printcap configuration for Kerberos authentication is very simple.

The kerberos_id is the principal name of the lpd server that clients will connect to. For backwards compatibility, kerberos_server_principal can also be used. This values is used to obtain a ticket for the lpd server, and is the only entry required for client to server authentication.

The other entries are used by the lpd server. kerberos_keytab entry is the location of the keytab file to be used by the server. This contains the passphrase used by the server to authenticate itself and get a ticket from the ticket server.

The kerberos_id value is also used by the server during the authentication process to make sure that the correct principal name was used by the request originator. This check has saved many hours of pain in trying to determine why authentication is failing.

The kerberos_life and kerberos_renew set the lifetime and renewability of the lpd server Kerberos tickets. These values should not be modified unless you are familiar with the Kerberos system. There are extensive notes in the LPRng source code concerning these values. The kerberos_service value supplies the name of the service to be used when generating a ticket. It is stronly recommended that the kerberos_id entry be used instead.

User Environment Variables and Files

In order to use kerberos authentication, the user will need to obtain a ticket from the Kerberos ticket server. This is done using kinit.

No other actions are required by the user.

14.15 Using Kerberos 4 for Authentication

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.

During configuration, if the krb.h (Kerberos 4) include file is found, then this is enabled by default.

Printcap Entries

Options used:

Example printcap entry:

pr:
    :lp=pr@wayoff
    :auth=kerberos4
    :kerberos_id=lpr/wayoff.astart.com@ASTART.COM

The configuration information for Kerberos4 and Kerberos5 is identical and differ only in the authentication type. Note that only client to server authentication is supported.

14.16 Using MD5 for Authentication

LPRng has built-in support for using MD5 digests as an authentication method. The implementation is provided as an example of how to add user level authentication into the LPRng system.

The method used to do authentication is very simple. Each user has a file containing a set of keys that are used to salt an md5 hash. The information being transferred has its md5 checksum calculated using this salt, and is then transferred to the destination, along with the md5 hash result. At the destination the server will get the user id, obtain the salt value from a key file, and then calculate the md5 hash value. If the two are in agreement, authentication is successful.

The keyfile used for md5 authentication contains an id followed by a text string whose binary value is used as a hash key:

id1=key
id2=key

Example:

lpr@h2=tadf79asd%^1asdf
lpr@h1=fdfa%$^&^%$

Printcap Entries

Options used:

Example printcap entry:

pr:
    :lp=pr@wayoff
    :auth=md5
    :md5_id=lpr@wayoff.com
pr:server
    :auth_forward=md5
    :md5_id=lpr@wayoff.com
    :md5_server_keyfile
    :md5_forward_id=lpr@faroff.com

The md5_id value is used by the client to obtain a hash key that is used to salt the md5 calculation for client to server transfers. The md5_forward_id value is used by the server to obtain a hash key that is used to salt the md5 calculation for server to server transfers.

The md5_server_keyfile contains the keys of users; the id sent as the connection information is used to obtain the key from the file.

To set up md5 authentication, all that is needed is the following.

User Environment Variables and Files

Options used:

The MD5KEYFILE environment variable contains the path to the user keytab file.

14.17 Adding Authentication Support

Additional types of authentication support can be added very easily to LPRng by using the following conventions and guidelines.

First, the authentication method can be connection based or transfer based. Connection based authentication involves the LPRng client or server opening a connection to the remote server, having the authentication protocol provide authentication information, and then having no further interaction with the system. This is the easiest to implement and understand method. Code needs to be provided to do a simple authentication exchange between the two ends of the connection, after which no other action needs to be taken.

Transfer based authentication is more complex, but allows encrypted transfers of information between the two systems. A connection is established between client and server (or server and server), and an initial protocol exchange is performed. Then the authentication module transfers the command or job information to the destination, where is it unpacked and/or decrypted. The internal LPD server facilities are then invoked by the authentication module, which also provides a destination for any error message or information destined for the client. The authentication module will encrpt or encode this information and then send it to the client program. This type of authentication is more complex, but provides a higher degree of security and reliability than the simple connection based system.

Printcap Support

By convention, printcap entries auth=XXX and auth_forward=XXX specifies that authentication protocol XXX is to be used for client to server and for server to server transfers respectively.

Similarly, the server receiving an authentication request must have a XXX_id=name entry in the printcap or configuration information. This allows several different authentication protocols to be accepted by a server.

By convention, printcap and configuration entries of the form XXX_key contain configuration information for the XXX authentication protocol. As part of the authentication support process the XXX_key values are extracted from the printcap and configuration files and placed in a simple database for the authentication support module.

If you are using a routing filter, then you can also place XXX_key information in the routing entry for each file, and this will be used for sending the job to the specified destination.

Code Support

The LPRng/src/common/sendauth.c file has the following entries at the end.

#define SENDING
#include "user_auth.stub"

struct security SendSecuritySupported[] = {
  /* name,       config_tag, connect,    send,   receive */
  { "kerberos4", "kerberos", Send_krb4_auth, 0, 0 },
  { "kerberos*", "kerberos", 0,           Krb5_send },
  { "pgp",       "pgp",      0,           Pgp_send },
#if defined(USER_SEND)
 USER_SEND
#endif
  {0}
};
This is an example of how to add user level authentication support. The user_auth.stub file contains the source code for the various modules authentication modules. You can replace this file with your own version if desired. The following fields are used.
name

The authentication name. The auth=XXX printcap or configuration value will cause the name fields to be searched using a glob match.

config_tag

When a match is found, the config_tag value is used to search the printcap and configuration entries for information. If the config_tag field has value XXX, then entries with keys XXX_key will be extracted for use by the authentication code.

connect

Routine to call to support connection level authentication. This routine is responsible for connection establishment and protocol handshake. If the value is 0, then the send field value will be used.

send

Routine to call to support transfer level authentication. The send routine is provided a file and a connection to the remote server, and is responsible for the transferring files.

The LPRng/src/common/lpd_secure.c file has the following information at the end:

#define RECEIVE 1
#include "user_auth.stub"

 struct security ReceiveSecuritySupported[] = {
    /* name, config_tag, connect, send, receive */
#if defined(HAVE_KRB_H) && defined(MIT_KERBEROS4)
    { "kerberos4", "kerberos",  0, 0, 0 },
#endif
#if defined(HAVE_KRB5_H)
    { "kerberos*", "kerberos",   0, 0, Krb5_receive },
#endif
    { "pgp",       "pgp",   0, 0, Pgp_receive, },
#if defined(USER_RECEIVE)
/* this should have the form of the entries above */
 USER_RECEIVE
#endif
    {0}
};

This information matches the same information in the sendauth.c file. When the authentication request arrives at the server, the name field values are searched for a match, and then the config_tag value is used to get extract configuration information from the database for the protocol.

The receive routine is then called and is expected to handle the remaining steps of the authentication protocol. If the routine exits with a 0 value then the lpd server expects connection level authentication has been done and proceeds to simply transfer information using the standard RFC1179 protocol steps. A non-zero return value indicates an error and an error is reported to the other end of the connection.

If the receive module is to perform transfer level authentication, then the module carries out the necessary steps to transfer the command and/or job information. It then calls the necessary internal LPRng routine to implement the desired services. After finishing the requested work, these routines return to the calling authentication module, which then will transfer data, close the connection to the remote system, and return to the calling system. The combination of 0 return value and closed connection indicates successful transfer level authentication to the server.

The user_auth.stub file contains the following code that sets the USER_SEND variable:

#if defined(SENDING)
extern int md5_send();
#  define USER_SEND \
  { "md5", "md5", md5_send, 0, md5_receive },
#endif

If the SENDING value has been defined, this causes the prototype for md5_send() to be place in the file and the USER_SEND value to be defined. This will cause the md5 authentication information to be placed in the correct table.

Connection and Transfer Authentication

Rather than go into a detailed description of the code, the user_auth.stub file contains extremely detailed examples as well as several working versions of authentication information. It is recommended that the user start with one of these and then modify it to suit themselves.


Next Previous Contents