Next Previous Contents

16. Authentication and Encryption

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.

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

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

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

16.4 Client Operations for Client To lpd Server Authentication

Options used:

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.

16.5 Server Operations for Client To lpd Server Authentication

Options used:

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.

16.6 lpd Server to Server Authentication

Options used:

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
<normal file contents>
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.

16.7 Permission Checking

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.

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

16.8 Using PGP for Authentication

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

PGP Configuration

Options used:

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 "$@"

Permissions

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

Client Configuration

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.

16.9 Using Kerberos 5 for Authentication

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.

Kerberos Installation Procedure

  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.

Testing Transfers

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.

Explicit Server Principal Name

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

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

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.


Next Previous Contents