Subject: [netatalk-admins] authenticated printing patch

From: andrew morgan <[email-masked]>
Date: Thu, 23 Dec 1999 22:26:19 -0800 (PST)

Attached to this email is the authenticated printing patch for papd.  This
patch also includes Andras Kadinger's binary patch and should be applied
to the pre-asun2.1.4-36a source.  To apply the patch, cd into the source
directory and type "patch -p1 < /path/to/papd-binary-auth-1.patch".

Pam support is required (it is the only authentication method supported
right now) and the patch uses the ClearTxt password method to exchange
data with the mac.  Authentication can be configured for each printer by
adding "au=pam" to the papd.conf file.  For example:

authprinter:\
        :pr=lp:au=pam:

If there are any problems or suggestions, feel free to email me.  I will
be away from email until 12/27.

	Andy
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/Makefile netatalk-papd_binary-auth/etc/papd/Makefile
--- netatalk-1.4b2+asun2.1.4/etc/papd/Makefile	Fri Jun  4 15:05:22 1999
+++ netatalk-papd_binary-auth/etc/papd/Makefile	Thu Dec 23 04:37:50 1999
@@ -1,13 +1,13 @@
 SRC=    main.c printcap.c session.c file.c comment.c lp.c ppd.c \
-	magics.c headers.c queries.c
+	magics.c headers.c queries.c pam.c
 OBJ=	main.o printcap.o session.o file.o comment.o lp.o ppd.o \
-	magics.o headers.o queries.o
+	magics.o headers.o queries.o pam.o
 
 INCPATH = -I../../include ${KRBINCPATH} ${ABSINCPATH}
 CFLAGS=	${DEFS} ${KRBDEFS} ${ABSDEFS} ${OPTOPTS} ${INCPATH}
 TAGSFILE=	tags
-LIBDIRS=	-L../../libatalk ${KRBLIBDIRS} ${ABSLIBDIRS}
-LIBS=	-latalk ${ABSLIBS} ${KRBLIBS} ${ADDLIBS}
+LIBDIRS=	-L../../libatalk ${KRBLIBDIRS} ${ABSLIBDIRS} ${PAMLIBDIRS}
+LIBS=	-latalk ${ABSLIBS} ${KRBLIBS} ${ADDLIBS} ${PAMLIBS} ${LIBSHARED}
 CC=	cc
 INSTALL=	install
 
@@ -18,10 +18,20 @@
 	    KRBINCPATH="-I${KRBDIR}/include"; \
 	    KRBDEFS="-DKRB"; \
 	fi; \
+	if [ x"${PAMDIR}" != x ]; then \
+	    PAMLIBS="-lpam"; \
+	    if [ "${PAMDIR}" != "/usr" ]; then \
+	      PAMLIBDIRS="-L${PAMDIR}/lib"; \
+	      PAMINCPATH="-I${PAMDIR}/include"; \
+	    fi; \
+	    PAMDEFS="-DUSE_PAM"; \
+	fi; \
         ${MAKE} ${MFLAGS} CC="${CC}" ADDLIBS="${ADDLIBS}" DEFS="${DEFS}" \
 	    OPTOPTS="${OPTOPTS}" DESTDIR="${DESTDIR}" \
 	    SBINDIR="${SBINDIR}" BINDIR="${BINDIR}" RESDIR="${RESDIR}" \
 	    ETCDIR="${ETCDIR}" LIBDIR="${LIBDIR}" INCDIR="${INCDIR}" \
+	    PAMLIBS="$${PAMLIBS}" PAMLIBDIRS="$${PAMLIBDIRS}" \
+	    PAMINCPATH="$${PAMINCPATH}" PAMDEFS="$${PAMDEFS}" \
 	    KRBLIBS="$${KRBLIBS}" KRBLIBDIRS="$${KRBLIBDIRS}" \
 	    KRBINCPATH="$${KRBINCPATH}" KRBDEFS="$${KRBDEFS}" papd
 
@@ -48,12 +58,19 @@
 FRC:
 
 papd : ${OBJ} ../../libatalk/libatalk.a
-	${CC} ${CFLAGS} ${LDFLAGS} -o papd ${OBJ} ${LIBDIRS} ${LIBS}
+	${CC} ${CFLAGS} ${PAMINCPATH} ${PAMDEFS} ${LDFLAGS} -o papd \
+	    ${OBJ} ${LIBDIRS} ${LIBS}
 
 main.o : main.c
 	${CC} ${CFLAGS} -D_PATH_PAPDCONF=\"${ETCDIR}/papd.conf\" \
 	    -DVERSION=\"`cat ../../VERSION`\" \
 	    ${CPPFLAGS} -c main.c
+
+pam.o : pam.c
+	${CC} ${CFLAGS} ${PAMDEFS} -c pam.c
+
+queries.o : queries.c
+	${CC} ${CFLAGS} ${PAMDEFS} -c queries.c
 
 install : all
 	${INSTALL} -c papd ${SBINDIR}
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/file.c netatalk-papd_binary-auth/etc/papd/file.c
--- netatalk-1.4b2+asun2.1.4/etc/papd/file.c	Wed Feb  3 12:01:45 1999
+++ netatalk-papd_binary-auth/etc/papd/file.c	Mon Dec  6 22:04:07 1999
@@ -11,56 +11,44 @@
 
 #include "file.h"
 
-markline( start, stop, pf )
-    char		**start, **stop;
+markline( pf, start, linelength, crlflength )
+    char		**start;
+    int			*linelength, *crlflength;
     struct papfile	*pf;
 {
     char		*p;
 
-    if ( PF_BUFSIZ( pf ) == 0 && ( pf->pf_state & PF_EOF )) {
+    if ( pf->pf_datalen == 0 && ( pf->pf_state & PF_EOF )) {
 	return( 0 );
     }
 
+    *start = pf->pf_data;
+
     /* get a line */
-    for ( p = pf->pf_cur; p < pf->pf_end; p++ ) {
-	if ( *p == '\n' || *p == '\r' ) {
+    for ( *linelength=0; *linelength < pf->pf_datalen; (*linelength)++) {
+	if (pf->pf_data[*linelength] == '\n' ||
+	    pf->pf_data[*linelength] == '\r') {
 	    break;
 	}
     }
-    if ( p >= pf->pf_end ) {
+
+    if ( *linelength >= pf->pf_datalen ) {
 	if ( pf->pf_state & PF_EOF ) {
 	    APPEND( pf, "\n", 1 );
-	} else {
+	} else if (*linelength < 1024) {
 	    return( -1 );
 	}
     }
 
-    *start = pf->pf_cur;
-    *stop = p;
-    if ( *stop == *start ) {
-	return( 1 );			/* don't return len 0 lines */
-    } else {
-	return( *stop - *start );
-    }
-}
-
-consumetomark( start, stop, pf )
-    char		*start, *stop;
-    struct papfile	*pf;
-{
-    if ( start != pf->pf_cur || pf->pf_cur > stop || stop > pf->pf_end ) {
-	abort();
-    }
+    p = pf->pf_data + *linelength;
 
-    pf->pf_cur = stop + 1;		/* past the stop char */
-    if ( pf->pf_cur > pf->pf_end ) {
-	abort();
-    }
-    if ( pf->pf_cur == pf->pf_end ) {
-	pf->pf_cur = pf->pf_end = pf->pf_buf;
+    *crlflength=0;
+    while(*crlflength < pf->pf_datalen-*linelength && 
+    (p[*crlflength]=='\r' || p[*crlflength]=='\n')) {
+	(*crlflength)++;
     }
 
-    return;
+    return *linelength;
 }
 
 morespace( pf, data, len )
@@ -71,15 +59,14 @@
     char		*nbuf;
     int			nsize;
 
-    if ( pf->pf_cur != pf->pf_buf ) {			/* pull up */
-	bcopy( pf->pf_cur, pf->pf_buf, PF_BUFSIZ( pf ));
-	pf->pf_end = pf->pf_buf + PF_BUFSIZ( pf );
-	pf->pf_cur = pf->pf_buf;
+    if ( pf->pf_data != pf->pf_buf ) {			/* pull up */
+	bcopy( pf->pf_data, pf->pf_buf, pf->pf_datalen);
+	pf->pf_data = pf->pf_buf;
     }
 
-    if ( pf->pf_end + len > pf->pf_buf + pf->pf_len ) {	/* make more space */
-	nsize = (( pf->pf_len + len ) / PF_MORESPACE +
-		(( pf->pf_len + len ) % PF_MORESPACE != 0 )) * PF_MORESPACE;
+    if ( pf->pf_datalen + len > pf->pf_bufsize ) {	/* make more space */
+	nsize = (( pf->pf_bufsize + len ) / PF_MORESPACE +
+		(( pf->pf_bufsize + len ) % PF_MORESPACE != 0 )) * PF_MORESPACE;
 	if ( pf->pf_buf ) {
 	    if (( nbuf = (char *)realloc( pf->pf_buf, nsize )) == 0 ) {
 		exit( 1 );
@@ -89,14 +76,13 @@
 		exit( 1 );
 	    }
 	}
-	pf->pf_len = nsize;
-	pf->pf_end = nbuf + ( pf->pf_end - pf->pf_buf );
-	pf->pf_cur = nbuf + ( pf->pf_cur - pf->pf_buf );
+	pf->pf_bufsize = nsize;
+	pf->pf_data = nbuf + ( pf->pf_data - pf->pf_buf );
 	pf->pf_buf = nbuf;
     }
 
-    bcopy( data, pf->pf_end, len );
-    pf->pf_end += len;
+    bcopy( data, pf->pf_data + pf->pf_datalen, len );
+    pf->pf_datalen += len;
 }
 
 spoolerror( out, str )
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/file.h netatalk-papd_binary-auth/etc/papd/file.h
--- netatalk-1.4b2+asun2.1.4/etc/papd/file.h	Tue May 20 10:35:42 1997
+++ netatalk-papd_binary-auth/etc/papd/file.h	Mon Dec  6 22:04:07 1999
@@ -6,10 +6,10 @@
 struct papfile {
     int			pf_state;
     struct state	*pf_xstate;
-    int			pf_len;
+    int			pf_bufsize;
+    int			pf_datalen;
     char		*pf_buf;
-    char		*pf_cur;
-    char		*pf_end;
+    char		*pf_data;
 };
 
 #define PF_BOT		(1<<0)
@@ -17,15 +17,16 @@
 #define PF_QUERY	(1<<2)
 
 #define APPEND( pf, data, len )	\
-	if ( (pf)->pf_end + (len) > (pf)->pf_buf + (pf)->pf_len ) { \
+	if ( (pf)->pf_data + (pf)->pf_datalen + (len) > \
+	(pf)->pf_buf + (pf)->pf_bufsize ) { \
 		morespace( (pf), (data), (len)); \
 	} else { \
-		bcopy( (data), (pf)->pf_end, (len)); \
-		(pf)->pf_end += (len); \
+		bcopy( (data), (pf)->pf_data+ (pf)->pf_datalen, (len)); \
+		(pf)->pf_datalen += (len); \
 	}
-#define PF_BUFSIZ( pf )		((pf)->pf_end - (pf)->pf_cur)
-#define CONSUME( pf, len )	(((pf)->pf_cur += (len)), \
-	(((pf)->pf_cur >= (pf)->pf_end) && \
-	((pf)->pf_cur = (pf)->pf_end = (pf)->pf_buf)))
+#define CONSUME( pf, len )	(((pf)->pf_data += (len)), \
+	((pf)->pf_datalen-=(len)), \
+	(((pf)->pf_datalen <= 0) && \
+	((pf)->pf_data = (pf)->pf_buf,(pf)->pf_datalen=0)))
 
 #define PF_MORESPACE	1024
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/headers.c netatalk-papd_binary-auth/etc/papd/headers.c
--- netatalk-1.4b2+asun2.1.4/etc/papd/headers.c	Thu May 29 17:29:48 1997
+++ netatalk-papd_binary-auth/etc/papd/headers.c	Mon Dec  6 22:04:07 1999
@@ -14,9 +14,10 @@
     struct papfile	*in, *out;
 {
     char		*start, *stop, *p, *q, c;
+    int			linelength, crlflength;
     struct comment	*comment = compeek();
 
-    switch ( markline( &start, &stop, in )) {
+    switch ( markline( in, &start, &linelength, &crlflength )) {
     case 0 :
 	return( 0 );
 
@@ -24,6 +25,7 @@
 	return( CH_MORE );
     }
 
+    stop = start + linelength;
     for ( p = start; p < stop; p++ ) {
 	if ( *p == ':' ) {
 	    break;
@@ -50,10 +52,9 @@
 	*q = c;
     }
 
-    *stop = '\n';
-    lp_write( start, stop - start + 1 );
+    lp_write( start, linelength + crlflength );
     compop();
-    consumetomark( start, stop, in );
+    CONSUME( in, linelength + crlflength );
     return( CH_DONE );
 }
 
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/lp.c netatalk-papd_binary-auth/etc/papd/lp.c
--- netatalk-1.4b2+asun2.1.4/etc/papd/lp.c	Thu Jun 26 13:48:43 1997
+++ netatalk-papd_binary-auth/etc/papd/lp.c	Mon Dec 13 21:19:11 1999
@@ -573,6 +573,7 @@
     struct papfile	*out;
 {
     char			buf[ 1024 ], *start, *stop, *p, *q;
+    int				linelength, crlflength;
     static struct papfile	pf;
     int				n, len, s;
 	
@@ -595,15 +596,16 @@
     }
 
     for (;;) {
-	if ( markline( &start, &stop, &pf ) > 0 ) {
+	if ( markline( &pf, &start, &linelength, &crlflength ) > 0 ) {
 	    /* parse */
+	    stop = start + linelength;
 	    for ( p = start; p < stop; p++ ) {
 		if ( *p == ' ' || *p == '\t' ) {
 		    break;
 		}
 	    }
 	    if ( p >= stop ) {
-		consumetomark( start, stop, &pf );
+		CONSUME( &pf , linelength + crlflength);
 		continue;
 	    }
 
@@ -614,7 +616,7 @@
 	    len = p - start;
 	    if ( len == strlen( kw_rank ) &&
 		    strncmp( kw_rank, start, len ) == 0 ) {
-		consumetomark( start, stop, &pf );
+		CONSUME( &pf, linelength + crlflength );
 		continue;
 	    }
 	    if (( len == strlen( kw_active ) &&
@@ -636,7 +638,7 @@
 		}
 		if ( p >= stop ) {
 		    APPEND( out, ".\n", 2 );
-		    consumetomark( start, stop, &pf );
+		    CONSUME( &pf, linelength + crlflength );
 		    continue;
 		}
 		APPEND( out, tag_owner, strlen( tag_owner ));
@@ -655,7 +657,7 @@
 		}
 		if ( p >= stop ) {
 		    APPEND( out, ".\n", 2 );
-		    consumetomark( start, stop, &pf );
+		    CONSUME( &pf , linelength + crlflength );
 		    continue;
 		}
 		APPEND( out, tag_job, strlen( tag_job ));
@@ -684,7 +686,7 @@
 		}
 		if ( p <= q ) {
 		    APPEND( out, ".\n", 2 );
-		    consumetomark( start, stop, &pf );
+		    CONSUME( &pf, linelength + crlflength );
 		    continue;
 		}
 		APPEND( out, tag_files, strlen( tag_files ));
@@ -700,16 +702,16 @@
 		APPEND( out, p, stop - p );
 		APPEND( out, "\n.\n", 3 );
 
-		consumetomark( start, stop, &pf );
+		CONSUME( &pf, linelength + crlflength );
 		continue;
 	    }
 
 	    /* status */
 	    APPEND( out, tag_status, strlen( tag_status ));
-	    APPEND( out, start, stop - start );
+	    APPEND( out, start, linelength );
 	    APPEND( out, "\n.\n", 3 );
 
-	    consumetomark( start, stop, &pf );
+	    CONSUME( &pf, linelength + crlflength );
 	} else {
 	    APPEND( out, "*\n", 2 );
 	    lp_disconn_unix( s );
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/magics.c netatalk-papd_binary-auth/etc/papd/magics.c
--- netatalk-1.4b2+asun2.1.4/etc/papd/magics.c	Thu May 29 17:28:03 1997
+++ netatalk-papd_binary-auth/etc/papd/magics.c	Mon Dec  6 22:04:07 1999
@@ -14,7 +14,8 @@
 ps( infile, outfile )
     struct papfile	*infile, *outfile;
 {
-    char			*start, *stop;
+    char			*start;
+    int				linelength, crlflength;
     struct comment		*comment;
 
     for (;;) {
@@ -31,7 +32,7 @@
 	    }
 
 	} else {
-	    switch ( markline( &start, &stop, infile )) {
+	    switch ( markline( infile, &start, &linelength, &crlflength )) {
 	    case 0 :
 		/* eof on infile */
 		outfile->pf_state |= PF_EOF;
@@ -43,7 +44,7 @@
 	    }
 
 	    if ( infile->pf_state & PF_BOT ) {
-		if (( comment = commatch( start, stop, magics )) != NULL ) {
+		if (( comment = commatch( start, start+linelength, magics )) != NULL ) {
 		    compush( comment );
 		    continue;	/* top of for (;;) */
 		}
@@ -57,9 +58,8 @@
 	    }
 
 	    /* write to file */
-	    *stop = '\n';
-	    lp_write( start, stop - start + 1 );
-	    consumetomark( start, stop, infile );
+	    lp_write( start, linelength + crlflength );
+	    CONSUME( infile, linelength + crlflength );
 	}
     }
 }
@@ -68,10 +68,11 @@
     struct papfile	*in, *out;
 {
     struct comment	*comment;
-    char		*start, *stop;
+    char		*start;
+    int			linelength, crlflength;
 
     for (;;) {
-	switch ( markline( &start, &stop, in )) {
+	switch ( markline( in, &start, &linelength, &crlflength )) {
 	case 0 :
 	    /* eof on infile */
 	    out->pf_state |= PF_EOF;
@@ -85,24 +86,25 @@
 	if ( in->pf_state & PF_BOT ) {
 	    in->pf_state &= ~PF_BOT;
 	} else {
-	    if (( comment = commatch( start, stop, queries )) != NULL ) {
+	    if (( comment = commatch( start, start+linelength, queries )) != NULL ) {
 		compush( comment );
 		return( CH_DONE );
 	    }
 	}
 
-	consumetomark( start, stop, in );
+	CONSUME( in, linelength + crlflength );
     }
 }
 
 cm_psadobe( in, out )
     struct papfile	*in, *out;
 {
-    char		*start, *stop;
+    char		*start;
+    int			linelength, crlflength;
     struct comment	*comment = compeek();
 
     for (;;) {
-	switch ( markline( &start, &stop, in )) {
+	switch ( markline( in, &start, &linelength, &crlflength )) {
 	case 0 :
 	    /* eof on infile */
 	    out->pf_state |= PF_EOF;
@@ -120,15 +122,14 @@
 		spoolerror( out, "Ignoring job." );
 	    }
 	} else {
-	    if (( comment = commatch( start, stop, headers )) != NULL ) {
+	    if (( comment = commatch( start, start + linelength, headers )) != NULL ) {
 		compush( comment );
 		return( CH_DONE );
 	    }
 	}
 
-	*stop = '\n';
-	lp_write( start, stop - start + 1 );
-	consumetomark( start, stop, in );
+	lp_write( start, linelength + crlflength );
+	CONSUME( in, linelength + crlflength );
     }
 }
 
@@ -138,9 +139,10 @@
     struct papfile	*in, *out;
 {
     char		*start, *stop, *p;
+    int			linelength, crlflength;
     struct comment	*comment = compeek();
 
-    switch ( markline( &start, &stop, in )) {
+    switch ( markline( in, &start, &linelength, &crlflength )) {
     case 0 :
 	/* eof on infile */
 	out->pf_state |= PF_EOF;
@@ -151,6 +153,7 @@
 	return( CH_MORE );
     }
 
+    stop = start + linelength;
     for ( p = start; p < stop; p++ ) {
 	if ( *p == ' ' || *p == '\t' ) {
 	    break;
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/main.c netatalk-papd_binary-auth/etc/papd/main.c
--- netatalk-1.4b2+asun2.1.4/etc/papd/main.c	Mon Jul  5 23:11:18 1999
+++ netatalk-papd_binary-auth/etc/papd/main.c	Mon Dec 13 21:27:16 1999
@@ -570,6 +570,18 @@
 	    strcpy( pr->p_printer, p );
 	}
 
+	/*
+	 * Do we want authenticated printing?
+	 */
+	if ( pgetstr( "au", &a ) == NULL ) {
+	    syslog(LOG_INFO, "%s: Auth off", pr->p_name);
+	    pr->p_flags &= ~P_AUTH;
+	} else {
+	    syslog(LOG_INFO, "%s: Auth on", pr->p_name);
+	    pr->p_flags |= P_AUTH;
+	}
+
+
 	if ( pr->p_flags & P_SPOOLED ) {
 	    /*
 	     * Get operator name.
@@ -714,9 +726,9 @@
 	 * Must Kerberos authenticate?
 	 */
 	if ( pgetflag( "ka" ) == 1 ) {
-	    pr->p_flags |= P_AUTH;
+	    pr->p_flags |= P_KRB;
 	} else {
-	    pr->p_flags &= ~P_AUTH;
+	    pr->p_flags &= ~P_KRB;
 	}
 #endif
 
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/pam.c netatalk-papd_binary-auth/etc/papd/pam.c
--- netatalk-1.4b2+asun2.1.4/etc/papd/pam.c	Wed Dec 31 16:00:00 1969
+++ netatalk-papd_binary-auth/etc/papd/pam.c	Tue Dec 21 21:36:42 1999
@@ -0,0 +1,155 @@
+#ifdef USE_PAM
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <security/pam_appl.h>
+
+#define PASSWDLEN 8
+
+/* Static variables used to communicate between the conversation function
+ * and the server_login function
+ */
+static pam_handle_t *pamh = NULL; 
+static char *hostname = "TestServer";
+static char *PAM_username;
+static char *PAM_password;
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+static int PAM_conv (int num_msg,
+                     const struct pam_message **msg,
+                     struct pam_response **resp,
+                     void *appdata_ptr) 
+{
+  struct pam_response *reply;
+  int count;
+  
+#define COPY_STRING(s) (s) ? strdup(s) : NULL
+  
+  if (num_msg < 1)
+    return PAM_CONV_ERR;
+
+  reply = (struct pam_response *) 
+    calloc(num_msg, sizeof(struct pam_response));
+
+  if (!reply)
+    return PAM_CONV_ERR;
+
+  for (count = 0; count < num_msg; count++) {
+    char *string = NULL;
+
+    switch (msg[count]->msg_style) {
+    case PAM_PROMPT_ECHO_ON:
+      if (!(string = COPY_STRING(PAM_username)))
+        goto pam_fail_conv;
+      break;
+    case PAM_PROMPT_ECHO_OFF:
+      if (!(string = COPY_STRING(PAM_password)))
+        goto pam_fail_conv;
+      break;
+    case PAM_TEXT_INFO:
+    case PAM_BINARY_PROMPT:
+      /* ignore it... */
+      break;
+    case PAM_ERROR_MSG:
+    default:
+      goto pam_fail_conv;
+    }
+
+    if (string) {  
+      reply[count].resp_retcode = 0;
+      reply[count].resp = string;
+      string = NULL;
+    }
+  }
+
+  *resp = reply;
+  return PAM_SUCCESS;
+
+pam_fail_conv:
+  for (count = 0; count < num_msg; count++) {
+    if (!reply[count].resp)
+      continue;
+    switch (msg[count]->msg_style) {
+    case PAM_PROMPT_ECHO_OFF:
+    case PAM_PROMPT_ECHO_ON:
+      free(reply[count].resp);
+      break;      
+    }
+  }
+  free(reply);
+  return PAM_CONV_ERR;
+}
+
+static struct pam_conv PAM_conversation = {
+  &PAM_conv,
+  NULL
+};
+
+
+/* cleartxt login */
+int pam_printer(username, password)
+	char	*username, *password;
+{
+    int PAM_error;
+
+    syslog(LOG_INFO, "cleartext papd: %s", username);
+    PAM_username = username;
+    PAM_password = password;
+
+    PAM_error = pam_start("netatalk", username, &PAM_conversation,
+                          &pamh);
+    if (PAM_error != PAM_SUCCESS) {
+	pam_end(pamh, PAM_error);
+	pamh = NULL;
+	return(-1);
+    }
+
+    pam_set_item(pamh, PAM_TTY, "papd");
+    pam_set_item(pamh, PAM_RHOST, hostname);
+    PAM_error = pam_authenticate(pamh,0);
+    if (PAM_error != PAM_SUCCESS) {
+	pam_end(pamh, PAM_error);
+	pamh = NULL;
+	return(-1);
+    }      
+
+    PAM_error = pam_acct_mgmt(pamh, 0);
+    if (PAM_error != PAM_SUCCESS) {
+	pam_end(pamh, PAM_error);
+	pamh = NULL;
+	return(-1);
+    }
+
+    PAM_error = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+    if (PAM_error != PAM_SUCCESS) {
+	pam_end(pamh, PAM_error);
+	pamh = NULL;
+	return(-1);
+    }
+
+    PAM_error = pam_open_session(pamh, 0);
+    if (PAM_error != PAM_SUCCESS) {
+	pam_end(pamh, PAM_error);
+	pamh = NULL;
+	return(-1);
+    }
+
+    return(0);
+}
+
+/* logout */
+void pam_printer_logout() {
+    pam_close_session(pamh, 0);
+    pam_end(pamh, 0);
+    pamh = NULL;
+}
+
+#endif	/* USE_PAM */
+
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/printer.h netatalk-papd_binary-auth/etc/papd/printer.h
--- netatalk-1.4b2+asun2.1.4/etc/papd/printer.h	Mon Jul  5 23:11:19 1999
+++ netatalk-papd_binary-auth/etc/papd/printer.h	Mon Dec 13 21:16:59 1999
@@ -50,6 +50,7 @@
 #define P_SPOOLED	(1<<1)
 #define P_REGISTERED	(1<<2)
 #define P_ACCOUNT	(1<<3)
-#define P_AUTH		(1<<4)
+#define P_KRB		(1<<4)
+#define P_AUTH		(1<<5)
 
 extern struct printer	*printer;
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/queries.c netatalk-papd_binary-auth/etc/papd/queries.c
--- netatalk-1.4b2+asun2.1.4/etc/papd/queries.c	Wed Feb  3 12:12:10 1999
+++ netatalk-papd_binary-auth/etc/papd/queries.c	Thu Dec 23 22:02:18 1999
@@ -28,10 +28,11 @@
     struct papfile	*in, *out;
 {
     char		*start, *stop, *p;
+    int			linelength, crlflength;
     struct comment	*comment = compeek();
 
     for (;;) {
-	switch ( markline( &start, &stop, in )) {
+	switch ( markline( in, &start, &linelength, &crlflength )) {
 	case 0 :
 	    return( 0 );
 
@@ -39,17 +40,19 @@
 	    return( CH_MORE );
 	}
 
+	stop = start+linelength;
+
 	if ( comgetflags() == 0 ) {	/* started */
 	    if ( comment->c_end ) {
 		comsetflags( 1 );
 	    } else {
 		compop();
-		consumetomark( start, stop, in );
+		CONSUME( in, linelength + crlflength );
 		return( CH_DONE );
 	    }
 	} else {
 	    /* return default */
-	    if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
+	    if ( comcmp( start, start+linelength, comment->c_end, 0 ) == 0 ) {
 		for ( p = start; p < stop; p++ ) {
 		    if ( *p == ':' ) {
 			break;
@@ -60,15 +63,14 @@
 		    p++;
 		}
 
-		*stop = '\n';
-		APPEND( out, p, stop - p + 1 );
+		APPEND( out, p, stop - p + crlflength );
 		compop();
-		consumetomark( start, stop, in );
+		CONSUME( in, linelength + crlflength );
 		return( CH_DONE );
 	    }
 	}
 
-	consumetomark( start, stop, in );
+	CONSUME( in, linelength + crlflength );
     }
 }
 
@@ -81,14 +83,15 @@
 cq_k4login( in, out )
     struct papfile	*in, *out;
 {
-    char		*start, *stop, *p;
+    char		*start, *p;
+    int			linelength, crlflength;
     unsigned char	*t;
     struct comment	*comment = compeek();
     KTEXT_ST		tkt;
     AUTH_DAT		ad;
     int			rc, i;
 
-    switch ( markline( &start, &stop, in )) {
+    switch ( markline( in, &start, &linelength, &crlflength )) {
     case 0 :
 	return( 0 );
 
@@ -102,6 +105,7 @@
     }
 
     bzero( &tkt, sizeof( tkt ));
+    stop = start+linelength;
     for ( i = 0, t = tkt.dat; p < stop; p += 2, t++, i++ ) {
 	*t = ( h2b( (unsigned char)*p ) << 4 ) +
 		h2b( (unsigned char)*( p + 1 ));
@@ -113,7 +117,7 @@
 	syslog( LOG_ERR, "cq_k4login: %s", krb_err_txt[ rc ] );
 	APPEND( out, LoginFailed, strlen( LoginFailed ));
 	compop();
-	consumetomark( start, stop, in );
+	CONSUME( in, linelength + crlflength );
 	return( CH_DONE );
     }
     syslog( LOG_INFO, "cq_k4login: %s.%s@%s", ad.pname, ad.pinst,
@@ -123,7 +127,7 @@
 
     APPEND( out, LoginOK, strlen( LoginOK ));
     compop();
-    consumetomark( start, stop, in );
+    CONSUME( in, linelength + crlflength);
     return( CH_DONE );
 }
 
@@ -132,11 +136,12 @@
 cq_uameth( in, out )
     struct papfile	*in, *out;
 {
-    char		*start, *stop;
+    char		*start;
+    int			linelength, crlflength;
     struct comment	*c, *comment = compeek();
 
     for (;;) {
-	switch ( markline( &start, &stop, in )) {
+	switch ( markline( in, &start, &linelength, &crlflength )) {
 	case 0 :
 	    return( 0 );
 
@@ -145,7 +150,7 @@
 	}
 
 	if ( comgetflags() == 0 ) {	/* start */
-	    if (( printer->p_flags & P_AUTH ) == 0 ) {	/* no kerberos */
+	    if (( printer->p_flags & P_KRB ) == 0 ) {	/* no kerberos */
 		if ( comswitch( queries, cq_default ) < 0 ) {
 		    syslog( LOG_ERR, "cq_uameth: can't find default!" );
 		    exit( 1 );
@@ -161,7 +166,7 @@
 	    }
 	}
 
-	consumetomark( start, stop, in );
+	CONSUME( in, linelength + crlflength );
     }
 }
 #endif KRB
@@ -214,6 +219,44 @@
 }
 #endif ABS_PRINT
 
+
+/*
+ * Handler for RBISpoolerID
+ */
+
+static const char *spoolerid = "(PAPD Spooler) 2.1 (2.1.4 pre-release)\n";
+
+gq_rbispoolerid( out )
+    struct papfile	*out;
+{
+    APPEND( out, spoolerid, strlen( spoolerid ));
+    return(0);
+}
+
+
+
+#ifdef USE_PAM
+/*
+ * Handler for RBIUAMListQuery
+ */
+
+static const char *papuamlist = "ClearTxtUAM\n*\n";
+static const char *nouams = "*\n";
+
+gq_rbiuamlist( out )
+    struct papfile      *out;
+{
+    if (printer->p_flags & P_AUTH) {
+	APPEND( out, papuamlist, strlen( papuamlist ));
+	return( 0 );
+    } else {
+	APPEND( out, nouams, strlen( nouams ));
+	return( 0 );
+    }
+}
+#endif USE_PAM
+
+
 struct genquery {
     char	*gq_name;
     int		(*gq_handler)();
@@ -222,6 +265,10 @@
 #ifdef notdef
     { "UMICHUserBalance", gq_balance },
 #endif 
+    { "RBISpoolerID",	gq_rbispoolerid },
+#ifdef USE_PAM
+    { "RBIUAMListQuery", gq_rbiuamlist },
+#endif
     { "UMICHListQueue", gq_true },
     { "UMICHDeleteJob", gq_true },
     { NULL },
@@ -231,12 +278,13 @@
     struct papfile	*in, *out;
 {
     char		*start, *stop, *p, *q;
+    int			linelength, crlflength;
     struct comment	*comment = compeek();
     struct genquery	*gq;

     for (;;) {
-	switch ( markline( &start, &stop, in )) {
+	switch ( markline( in, &start, &linelength, &crlflength )) {
 	case 0 :
 	    return( 0 );
 
@@ -244,6 +292,8 @@
 	    return( CH_MORE );
 	}
 
+	stop = start+linelength;
+
 	if ( comgetflags() == 0 ) {	/* started */
 	    comsetflags( 1 );
 
@@ -282,12 +332,12 @@
 	} else {
 	    if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
 		compop();
-		consumetomark( start, stop, in );
+		CONSUME( in, linelength + crlflength );
 		return( CH_DONE );
 	    }
 	}
 
-	consumetomark( start, stop, in );
+	CONSUME( in, linelength + crlflength );
     }
 }
 
@@ -332,10 +382,11 @@
     struct papfile	*in, *out;
 {
     char		*start, *stop, *p;
+    int			linelength, crlflength;
     struct comment	*comment = compeek();
 
     for (;;) {
-	switch ( markline( &start, &stop, in )) {
+	switch ( markline( in, &start, &linelength, &crlflength )) {
 	case 0 :
 	    return( 0 );
 
@@ -343,6 +394,8 @@
 	    return( CH_MORE );
 	}
 
+	stop = start + linelength;
+
 	if ( comgetflags() == 0 ) {
 	    comsetflags( 1 );
 
@@ -372,13 +425,13 @@
 		if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
 		    APPEND( out, "*\n", 2 );
 		    compop();
-		    consumetomark( start, stop, in );
+		    CONSUME( in, linelength + crlflength );
 		    return( CH_DONE );
 		}
 	    }
 	}
 
-	consumetomark( start, stop, in );
+        CONSUME( in, linelength + crlflength );
     }
 }
 
@@ -386,11 +439,12 @@
     struct papfile	*in, *out;
 {
     char		*start, *stop, *p;
+    int			linelength, crlflength;
     struct comment	*comment = compeek();
     struct ppd_feature	*pfe;
 
     for (;;) {
-	switch ( markline( &start, &stop, in )) {
+	switch ( markline( in, &start, &linelength, &crlflength )) {
 	case 0 :
 	    return( 0 );
 
@@ -398,6 +452,8 @@
 	    return( CH_MORE );
 	}
 
+	stop = start + linelength;
+
 	if ( comgetflags() == 0 ) {
 	    comsetflags( 1 );
 
@@ -425,12 +481,12 @@
 	} else {
 	    if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
 		compop();
-		consumetomark( start, stop, in );
+		CONSUME( in, linelength + crlflength );
 		return( CH_DONE );
 	    }
 	}
 
-	consumetomark( start, stop, in );
+	CONSUME( in, linelength + crlflength );
     }
 }
 
@@ -440,12 +496,13 @@
 cq_printer( in, out )
     struct papfile	*in, *out;
 {
-    char		*start, *stop, *p;
+    char		*start, *p;
+    int			linelength, crlflength;
     struct comment	*c, *comment = compeek();
     struct ppd_feature	*pdpsver, *pdprod;
 
     for (;;) {
-	switch ( markline( &start, &stop, in )) {
+	switch ( markline( in, &start, &linelength, &crlflength )) {
 	case 0 :
 	    return( 0 );
 
@@ -498,14 +555,14 @@
 	    APPEND( out, pdprod->pd_value, strlen( pdprod->pd_value ));
 	    APPEND( out, "\r", 1 );
 	} else {
-	    if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
+	    if ( comcmp( start, start+linelength, comment->c_end, 0 ) == 0 ) {
 		compop();
-		consumetomark( start, stop, in );
+		CONSUME( in, linelength + crlflength );
 		return( CH_DONE );
 	    }
 	}
 
-	consumetomark( start, stop, in );
+	CONSUME( in, linelength + crlflength );
     }
 }
 
@@ -516,9 +573,10 @@
     struct papfile	*in, *out;
 {
     char		*start, *stop, *p;
+    int			linelength, crlflength;
     int			job;
 
-    switch ( markline( &start, &stop, in )) {
+    switch ( markline( in, &start, &linelength, &crlflength )) {
     case 0 :
 	return( 0 );
 
@@ -526,6 +584,8 @@
 	return( CH_MORE );
     }
 
+    stop = start + linelength;
+
     for ( p = start; p < stop; p++ ) {
 	if ( *p == ' ' || *p == '\t' ) {
 	    break;
@@ -546,16 +606,17 @@
     }
 
     compop();
-    consumetomark( start, stop, in );
+    CONSUME( in, linelength + crlflength );
     return( CH_DONE );
 }
 
 cq_listq( in, out )
     struct papfile	*in, *out;
 {
-    char		*start, *stop;
+    char		*start;
+    int			linelength, crlflength;
 
-    switch ( markline( &start, &stop, in )) {
+    switch ( markline( in, &start, &linelength, &crlflength )) {
     case 0 :
 	return( 0 );
 
@@ -568,10 +629,97 @@
     }
 
     compop();
-    consumetomark( start, stop, in );
+    CONSUME( in, linelength + crlflength );
     return( CH_DONE );
 }
 
+
+#ifdef USE_PAM
+/*
+ * Handler for RBILogin
+ */
+
+static const char *rbiloginok = "0\r";
+static const char *rbiloginbad = "-1\r";
+static const char *rbiloginerrstr = "%%[Error: SecurityError; \
+SecurityViolation: Unknown user, incorrect password or log on is \
+disabled ]%%\r%%Flushing: rest of job (to end-of-file) will be \
+ignored ]%%\r";
+
+cq_rbilogin( in, out )
+    struct papfile      *in, *out;
+{
+    char        *start, *stop, *p, *q;
+    int		linelength, crlflength;
+    char        username[9] = "\0";
+    char        password[9] = "\0";
+    struct comment      *comment = compeek();
+
+    for (;;) {
+        switch ( markline( in, &start, &linelength, &crlflength )) {
+        case 0 :
+            return( 0 );
+
+        case -1 :
+            return( CH_MORE );
+        }
+
+	stop = start + linelength;
+
+        if ( comgetflags() == 0 ) { /* first line */
+            for ( p = start + strlen( comment->c_begin ); p < stop; p++ ) {
+                if ( *p == '(' ) {
+                    p++;
+                    break;
+                }
+            }
+
+            for ( q = p; q < stop; q++ ) { 
+                if ( *q == ')' ) {
+                    break;
+                }
+            }
+
+            strncat(username, p, q - p);
+
+            for ( p = q; p < stop; p++ ) { /* Look for password */
+                if ( *p == '(' ) {
+                    p++;
+                    break;
+                }
+            }
+
+            for ( q = p; q < stop; q++ ) {
+                if ( *q == ')' ) {
+                    break;
+                }
+            }
+
+            strncat(password, p, q - p);
+            if ( (pam_printer(username,password)) == 0 ) {
+                pam_printer_logout();
+                lp_person( username );
+                syslog( LOG_INFO, "RBILogin: %s",username );
+                APPEND( out, rbiloginok, strlen( rbiloginok ));
+            } else {
+                syslog(LOG_INFO, "Bad RBILogin: %s",username);
+                APPEND( out, rbiloginbad, strlen( rbiloginbad ));
+                APPEND( out, rbiloginerrstr, strlen( rbiloginerrstr ));
+            }
+            comsetflags( 1 );
+        } else {
+            if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
+                compop();
+                return( CH_DONE );
+            }
+        }
+
+        CONSUME( in, linelength + crlflength );
+    }
+}
+#endif USE_PAM
+
+
 /*
  * All queries start with %%?Begin and end with %%?End.  Note that the
  * "Begin"/"End" general queries have to be last.
@@ -583,6 +731,9 @@
 #endif KRB
     { "%UMICHListQueue", 0,				cq_listq, C_FULL },
     { "%UMICHDeleteJob", 0,				cq_rmjob,	0 },
+#ifdef USE_PAM
+    { "%%?BeginQuery: RBILogin ", "%%?EndQuery",	cq_rbilogin,	0 },
+#endif USE_PAM
     { "%%?BeginQuery",		"%%?EndQuery",		cq_query,	0 },
     { "%%?BeginFeatureQuery",	"%%?EndFeatureQuery",	cq_feature,	0 },
     { "%%?BeginFontQuery",	"%%?EndFontQuery",	cq_font,	0 },
diff -urP netatalk-1.4b2+asun2.1.4/etc/papd/session.c netatalk-papd_binary-auth/etc/papd/session.c
--- netatalk-1.4b2+asun2.1.4/etc/papd/session.c	Fri Feb  5 22:42:47 1999
+++ netatalk-papd_binary-auth/etc/papd/session.c	Mon Dec  6 22:04:07 1999
@@ -59,16 +59,16 @@
     u_char		readport;
 
     infile.pf_state = PF_BOT;
-    infile.pf_len = 0;
+    infile.pf_bufsize = 0;
+    infile.pf_datalen = 0;
     infile.pf_buf = 0;
-    infile.pf_cur = 0;
-    infile.pf_end = 0;
+    infile.pf_data = 0;
 
     outfile.pf_state = PF_BOT;
-    outfile.pf_len = 0;
+    outfile.pf_bufsize = 0;
+    outfile.pf_datalen = 0;
     outfile.pf_buf = 0;
-    outfile.pf_cur = 0;
-    outfile.pf_end = 0;
+    outfile.pf_data = 0;
 
     /*
      * Ask for data.
@@ -170,7 +170,7 @@
 		 * If we're in the middle of a file, clean up.
 		 */
 		if (( infile.pf_state & PF_BOT ) ||
-			( PF_BUFSIZ( &infile ) == 0 &&
+			( infile.pf_datalen == 0 &&
 			( infile.pf_state & PF_EOF ))) {
 		    lp_print();
 		} else {
@@ -262,17 +262,17 @@
 
 	/* send any data that we have */
 	if ( readpending &&
-		( PF_BUFSIZ( &outfile ) || ( outfile.pf_state & PF_EOF ))) {
+		( outfile.pf_datalen || ( outfile.pf_state & PF_EOF ))) {
 	    for ( i = 0; i < quantum; i++ ) {
 		((char *)niov[ i ].iov_base)[ 0 ] = connid;
 		((char *)niov[ i ].iov_base)[ 1 ] = PAP_DATA;
 		((char *)niov[ i ].iov_base)[ 2 ] =
 			((char *)niov[ i ].iov_base)[ 3 ] = 0;
 
-		if ( PF_BUFSIZ( &outfile ) > PAP_MAXDATA  ) {
+		if ( outfile.pf_datalen > PAP_MAXDATA  ) {
 		    cc = PAP_MAXDATA;
 		} else {
-		    cc = PF_BUFSIZ( &outfile );
+		    cc = outfile.pf_datalen;
 		    if ( outfile.pf_state & PF_EOF ) {
 			((char *)niov[ 0 ].iov_base)[ 2 ] = 1;	/* eof */
 			outfile.pf_state = PF_BOT;
@@ -281,9 +281,9 @@
 		}
 
 		niov[ i ].iov_len = 4 + cc;
-		bcopy( outfile.pf_cur, niov[ i ].iov_base + 4, cc );
+		bcopy( outfile.pf_data, niov[ i ].iov_base + 4, cc );
 		CONSUME( &outfile, cc );
-		if ( PF_BUFSIZ( &outfile ) == 0 ) {
+		if ( outfile.pf_datalen == 0 ) {
 		    i++;
 		    break;
 		}