2000/03/04
This readme documents the changes I have made to papd to implement Apple's
-Print Server Security Protocol. With these patches and appropriate
+Print Server Security Protocol (PSSP). With these patches and appropriate
configuration choices in papd.conf, a client machine will be required to
authenticate to papd with a username or userame/password pair before papd
will spool the print job to lpr. This requires LaserWriter 8.6.1+ on the
Currently, only uams_guest.so, uams_passwd.so, and uams_pam.so
authentication modules are supported.
-To enable authentication on a particular printer, add the "au" flag to
-that printer's entry in papd.conf. To define which uams to use for
+To enable PSSP authentication on a particular printer, add the "sp" flag
+to that printer's entry in papd.conf. To define which uams to use for
authentication, use an "am" entry. The uams defined apply globally, to
all printers. It is not currently possible to define different
authentication methods for different printers. Here is an example printer
lp:\
:pr=|/usr/bin/lpr -Plp:\
- :au:\
+ :sp:\
:am=uams_guest.so,uams_clrtxt.so:\
:pd=/usr/local/atalk/etc/ppds/hp8100.ppd:
Macs and only on Linux. If there are any problems or feedback you'd like
to give, feel free to send me email.
-Hopefully these patches will be incorporated into Adrian Sun's standard
-netatalk distributions, but until then you can find it at:
-http://web.orst.edu/~morgan/netatalk/
+2000/07/31
+
+I've also added CAP-style authenticated printing. For those that aren't
+familiar, this requires that a user login to a file share before they can
+print. The file server stores the user's login name in a file named after
+the client machine's Appletalk address. The print server then reads the
+login name when the client machine tries to print. You'll need to set a
+directory where afpd store these files. This is a compile-time option set
+in the top-level Makefile. Look for the CAPDIR setting.
+
+You enable CAP or PSSP (Print Server Security Protocol) authentication on
+a printer by printer basis, and you can use any combination of these two.
+If both methods are enabled for a particular printer, CAP authentication
+will be tried first, then it will fall back to PSSP.
+
+The printcap flag to enable CAP is "ca", and the printcap flag to enable
+PSSP is "sp".
+
Enjoy!
# :pr=lp:op=wes:\
# :pd=/usr/share/lib/ppd/HPLJ_4M.PPD:
#
-# An example with authenticated printing:
+# An example with authenticated printing (see README.MORGAN):
# authprn:\
# :pr=|/usr/bin/lpr -Plp:\
# :pd=/usr/share/lib/ppd/HPLJ_4M.PPD:\
-# :au:\
+# :sp:ca:\
# :am=uams_clrtxt.so:
#
# Note also that papd.conf can list several printers.
magics.o headers.o queries.o auth.o uam.o
INCPATH = -I../../include ${KRBINCPATH} ${ABSINCPATH}
-CFLAGS= ${DEFS} ${KRBDEFS} ${ABSDEFS} ${OPTOPTS} ${INCPATH}
+CFLAGS= ${DEFS} ${KRBDEFS} ${ABSDEFS} ${CAPDEFS} ${OPTOPTS} ${INCPATH}
TAGSFILE= tags
LIBDIRS= -L../../libatalk ${KRBLIBDIRS} ${ABSLIBDIRS} ${PAMLIBDIRS}
LIBS= -latalk ${ABSLIBS} ${KRBLIBS} ${ADDLIBS} ${PAMLIBS} ${LIBSHARED}
fi; \
PAMDEFS="-DUSE_PAM"; \
fi; \
+ if [ x"${CAPDIR}" != x ]; then \
+ CAPDEFS="-DCAPDIR='\"${CAPDIR}\"'"; \
+ fi; \
${MAKE} ${MFLAGS} CC="${CC}" ADDLIBS="${ADDLIBS}" DEFS="${DEFS}" \
OPTOPTS="${OPTOPTS}" DESTDIR="${DESTDIR}" \
SBINDIR="${SBINDIR}" BINDIR="${BINDIR}" RESDIR="${RESDIR}" \
PAMLIBS="$${PAMLIBS}" PAMLIBDIRS="$${PAMLIBDIRS}" \
PAMINCPATH="$${PAMINCPATH}" PAMDEFS="$${PAMDEFS}" \
KRBLIBS="$${KRBLIBS}" KRBLIBDIRS="$${KRBLIBDIRS}" \
- KRBINCPATH="$${KRBINCPATH}" KRBDEFS="$${KRBDEFS}" papd showppd
+ KRBINCPATH="$${KRBINCPATH}" KRBDEFS="$${KRBDEFS}" \
+ CAPDEFS="$${CAPDEFS}" papd showppd
# UMICH stuff. Don't ask, I'm not telling.
CRAP=/afs/umich.edu/group/itd/software/packages
char hostname[ MAXHOSTNAMELEN ];
+extern struct sockaddr_at *sat;
+
/* initialize printing interface */
int lp_init();
/* cancel current job */
*q = '\0';
}
-lp_init( out )
+lp_init( out, sat )
struct papfile *out;
+ struct sockaddr_at *sat;
{
int fd, n, len;
char *cp, buf[ BUFSIZ ];
struct stat st;
+ int authenticated = 0;
#ifdef ABS_PRINT
char cost[ 22 ];
char balance[ 22 ];
#endif ABS_PRINT
+#ifdef CAPDIR
+ char username[32];
+ int addr_net, addr_node;
+ FILE *cap_file;
+ struct stat cap_st;
+ char addr_filename[256];
+#endif /* CAPDIR */
if ( printer->p_flags & P_AUTH ) {
- if ( lp.lp_person == NULL ) {
+ authenticated = 0;
+#ifdef CAPDIR
+ if ( printer->p_flags & P_AUTH_CAP ) {
+ addr_net = ntohs( sat->sat_addr.s_net );
+ addr_node = sat->sat_addr.s_node;
+ sprintf(addr_filename, "%s/net%d.%dnode%d", CAPDIR, addr_net/256, addr_net%256, addr_node);
+ if (stat(addr_filename, &cap_st) == 0) {
+ if ((cap_file = fopen(addr_filename, "r")) != NULL) {
+ if (fscanf(cap_file, "%s", username) != EOF) {
+ if (getpwnam(username) != NULL ) {
+ syslog(LOG_INFO, "CAP authenticated %s", username);
+ lp_person(username);
+ authenticated = 1;
+ } else {
+ syslog(LOG_INFO, "CAP error: invalid username: '%s'", username);
+ }
+ } else {
+ syslog(LOG_INFO, "CAP error: could not read username");
+ }
+ } else {
+ syslog(LOG_INFO, "CAP error: %m");
+ }
+ } else {
+ syslog(LOG_INFO, "CAP error: %m");
+ }
+ }
+#endif /* CAPDIR */
+
+ if ( printer->p_flags & P_AUTH_PSSP ) {
+ if ( lp.lp_person != NULL ) {
+ authenticated = 1;
+ }
+ }
+
+ if ( authenticated == 0 ) {
syslog( LOG_ERR, "lp_init: must authenticate" );
spoolerror( out, "Authentication required." );
return( -1 );
}
+
#ifdef ABS_PRINT
if (( printer->p_flags & P_ACCOUNT ) && printer->p_pagecost > 0 &&
! ABS_canprint( lp.lp_person, printer->p_role,
return( 0 );
}
-lp_open( out )
+lp_open( out, sat )
struct papfile *out;
+ struct sockaddr_at *sat;
{
char name[ MAXPATHLEN ];
int fd;
- if (( lp.lp_flags & LP_INIT ) == 0 && lp_init( out ) != 0 ) {
+ if (( lp.lp_flags & LP_INIT ) == 0 && lp_init( out, sat ) != 0 ) {
return( -1 );
}
if ( lp.lp_flags & LP_OPEN ) {
#include "file.h"
#include "comment.h"
-ps( infile, outfile )
+ps( infile, outfile, sat )
struct papfile *infile, *outfile;
+ struct sockaddr_at *sat;
{
char *start;
int linelength, crlflength;
for (;;) {
if ( comment = compeek()) {
- switch( (*comment->c_handler)( infile, outfile )) {
+ switch( (*comment->c_handler)( infile, outfile, sat )) {
case CH_DONE :
continue;
infile->pf_state &= ~PF_BOT;
/* set up spool file */
- if ( lp_open( outfile ) < 0 ) {
+ if ( lp_open( outfile, sat ) < 0 ) {
syslog( LOG_ERR, "lp_open failed" );
spoolerror( outfile, "Ignoring job." );
}
}
}
-cm_psquery( in, out )
+cm_psquery( in, out, sat )
struct papfile *in, *out;
+ struct sockaddr_at *sat;
{
struct comment *comment;
char *start;
}
}
-cm_psadobe( in, out )
+cm_psadobe( in, out, sat )
struct papfile *in, *out;
+ struct sockaddr_at *sat;
{
char *start;
int linelength, crlflength;
if ( in->pf_state & PF_BOT ) {
in->pf_state &= ~PF_BOT;
- if ( lp_open( out ) < 0 ) {
+ if ( lp_open( out, sat ) < 0 ) {
syslog( LOG_ERR, "lp_open failed" );
spoolerror( out, "Ignoring job." );
}
char *Query = "Query";
-cm_psswitch( in, out )
+cm_psswitch( in, out, sat )
struct papfile *in, *out;
+ struct sockaddr_at *sat;
{
char *start, *stop, *p;
int linelength, crlflength;
/*
* Do we want authenticated printing?
*/
- if ( pgetflag( "au", &a ) == 1 ) {
+ if ( pgetflag( "ca", &a ) == 1 ) {
pr->p_flags |= P_AUTH;
- } else {
- pr->p_flags &= ~P_AUTH;
+ pr->p_flags |= P_AUTH_CAP;
+ }
+ if ( pgetflag( "sp", &a ) == 1 ) {
+ pr->p_flags |= P_AUTH;
+ pr->p_flags |= P_AUTH_PSSP;
}
if ((p = pgetstr("am", &a)) != NULL ) {
#define P_ACCOUNT (1<<3)
#define P_KRB (1<<4)
#define P_AUTH (1<<5)
+#define P_AUTH_PSSP (1<<6)
+#define P_AUTH_CAP (1<<7)
extern struct printer *printer;
{
char uamnames[128] = "\0";
- if (printer->p_flags & P_AUTH) {
+ if (printer->p_flags & P_AUTH_PSSP) {
if (getuamnames(UAM_SERVER_PRINTAUTH, uamnames) < 0) {
append(out, nouams, strlen(nouams));
return(0);
}
/* move data */
- if ( ps( &infile, &outfile ) < 0 ) {
+ if ( ps( &infile, &outfile, sat ) < 0 ) {
syslog( LOG_ERR, "parse: bad return" );
exit( 1 ); /* really? close? */
}