LPRng-HOWTO: Authentication and Encryption

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

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

## 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

> `

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 Authentication Operations

Options used:

- `auth=`client to server authentication type
- `auth_forward=`server to server authentication type
- `XX_id=`server identification
- `XX_forward_id=`Server identification

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=kerberos5` 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.

## 16.5 Permission Checking

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

- AUTH
  This value is `true` or `match` if an authenticated request was received.
- AUTHTYPE=authtype
  This has the value of the `authtype` field in the authentication request.
- AUTHUSER=userinfo
  This is the `AUTHUSER` information provided by the authentication protocol, and is usually the originating user's identification.
- AUTHFROM=frominfo
  This is the `AUTHUSER` information provided by the authentication protocol, and is usually the originating system (user or lpd server) identification.
- AUTHSAMEUSER
  This item has effect only when checking jobs in a spool queue. The `AUTHUSER` information from the request is compared to the `AUTHUSER` information from the request that created a job. If they are identical, the match succeeds.
- AUTHJOB This item has effect only when checking jobs in a spool queue. If the job was transfered using an authentication protocol the match succeeds.

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

> `

## 16.6 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.

- The `user` and `group` configuration entry (defaults `daemon` and `daemon` respectively) specify the user and group id used by the `lpd` server for file and program execution. PGP uses the current user id of the PGP process to determine the locations of various configuration files and information. In this discussion we will assume that `lpd` runs as uid `daemon`.
- By default, the PGP program expects the public and secret key rings to be in the `$HOME/.pgp/` directory to be readable only by the user. In order to set up PGP authentication, make sure that the `daemon` account has a home directory. Then use the `su daemon` command to change effective UID to daemon and run the `pgp -kg` (generate key) command as daemon. The `daemon` user should not have a password.
- Each PGP key has an associated identifier. It is recommended that the `lpd` key be `lpr@hostname`, where hostname is the fully qualified domain name of the server. A public and a private key file will be created.
- Next, place the passphrase for the `daemon` user in `~daemon/.pgp/serverkey`, and make sure it has owner `daemon` and `600` permissions (read/write only by `daemon`). This is extremely important. If other users can read this file then security will be severely compromised.
- Next, distribute the `lpr@hostname` public key to all users of the LPRng server. This is usually done by placing the public key in a well known file location or making it available to users by some form of Public Key Distribution system (PKD). The key can be extracted and put into a text file using the following commands:

  > `

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

  > `

- To allow a user to send files to the server, their public key must be put into the `daemon` public key ring. This can be done 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:

  > `

  >     su daemon
  >     pgp -ka /tmp/keyfile ~daemon/.pgp/pubring.pgp

  > `

- If the `lpd` server is using PGP to forward jobs or requests, the destination server's public key must be put in the originating servers public keyring. For example:

  > `

  >     su daemon
  >     pgp -ka /tmp/lpd.keyfile ~daemon/.pgp/pubring.pgp

  > `

### Printcap Configuration

Options used:

- `pgp_path=`path to PGP program
- `pgp_id=`destination server key used by clients
- `pgp_forward_id=`destination server used by server
- `pgp_server_key=`path to server passphrase file

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:

- `PGPPASSFILE=`File to read PGP passphrase from
- `PGPPASSFD=`File descriptor to read PGP passphrase from
- `PGPPASS=`PGP passphrase

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

- Put the passphrase in a file, say `$(HOME)/.pgp/.hidden`, and set the `PGPPASSFILE` environment variable to the file name. This file will be opened and read by PGP to get the passphrase. This file should be owned by the user and have `0600` or read/write only by user permissions.
- 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 "$@"

  > `

- The least desirable method is to put the passphrase in the `PGPPASS` environment variable. Since the `ps` command can be used to list the environment variables of processes, this is highly undesireable and should not be used under any circumstances.

## 16.7 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.

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

### 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.
8. Do this for all the servers. You should use fully qualified domain names for the principals.
9. Now you need to extract the keytab for each of the servers:

   > `

   >     kadmin ...
   >     ktadd -k file_for_host  lpr/hostname.REALM

   > `

10. The 'file_for_host' contains the keytab information, which is the equivalent information for the server.
11. 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

    > `

### Printcap Entries

Options used:

- `auth=kerberos5=`use Kerberos5 authentication
- `kerberos_id=`destination server key used by clients
- `kerberos_server_principal=`alias for kerberos_id
- `kerberos_forward_id=`destination server used by server
- `kerberos_forward_principal=`alias for kerberos_forward_id
- `kerberos_keytab=`location of the lpd server keytab file
- `kerberos_service=`service to be used
- `kerberos_life=`lpd server ticket lifetime
- `kerberos_renew=`lpd server ticket renew

Example printcap entry:

> `

>     pr:
>         :lp=pr@wayoff
>         :auth=kerberos5
>         :kerberos_id=lpr@wayoff.ASTART.COM
>     pr:server
>         :lp=pr@faroff
>         :auth_forward=kerberos5
>         :kerberos_id=lpr@wayoff.ASTART.COM
>         :kerberos_forward_id=lpr@faroff.ASTART.COM
>         :kerberos_keytab=/etc/krb5.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.

## 16.8 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.

> `

>     cd LPRng
>     ./configure
>     make MIT_KERBEROS4=1

> `

### Printcap Entries

Options used:

- `auth=kerberos4`use Kerberos4 authentication
- `kerberos_id=`destination server key used by clients
- `kerberos_server_principal=`alias for kerberos_id

Example printcap entry:

> `

>     pr:
>         :lp=pr@wayoff
>         :auth=kerberos4
>         :kerberos_id=lpr@wayoff.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.

## 16.9 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:

- `auth=md5`use MD5 authentication
- `auth_forward=md5`forward using MD5 authentication
- `md5_id=`id for server
- `md5_forward_id=`id for server
- `md5_server_keyfile=`server keyfile

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.

- For each user generate a key and place it in the server keyfile. This file should have the form:

  > `

  >     user1@host1=asdfasdfadf
  >     user2@host2=a8789087asddasdf

  > `

- Assign a key to the server, and set its printcap entry to this key.

  > `

  >     pr:
  >         :lp=pr@wayoff
  >         :auth=md5
  >         :md5_id=lpr@wayoff.com

  > `

- For each user, create a user key file with the following format:

  > `

  >     lpr@wayoff=user1@host1 asdfasdfadf

  > `

  The first entry corresponds to the `md5_id` value in the printcap. The second field is the `AUTHUSER` value supplied to the server and which will be used to look up the key in the servers key file. Finally, the last field is the salt value for the md5 calculation.

### User Environment Variables and Files

Options used:

- `MD5KEYFILE=5`location of user keyfile

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

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