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

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

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

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