From: morgana Date: Fri, 28 Jul 2000 06:27:37 +0000 (+0000) Subject: Initial patch for authenticated printing. Requires LaserWriter 8.5.1 or X-Git-Tag: netatalk-1-5-rc1~764 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=33cdcb8d9746a9594df782e5a4f200f4ab61585f;hp=1c48539d061c18961002650ad1047e8ba8af7d2e;p=netatalk.git Initial patch for authenticated printing. Requires LaserWriter 8.5.1 or greater on client. See README.MORGAN for information. --- diff --git a/README.MORGAN b/README.MORGAN new file mode 100644 index 00000000..d751c6e4 --- /dev/null +++ b/README.MORGAN @@ -0,0 +1,49 @@ +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 +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 +client Mac. Papd will switch to the username provided by the client and +print as that user. + +Papd will now respond to the following Postscript queries: +RBISpoolerID +RBIUAMListQuery +RBILogin + +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 +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 +setup for papd.conf: + +lp:\ + :pr=|/usr/bin/lpr -Plp:\ + :au:\ + :am=uams_guest.so,uams_clrtxt.so:\ + :pd=/usr/local/atalk/etc/ppds/hp8100.ppd: + +Or see the example papd.conf. + +This patch also includes the patches by Andras Kadinger to enable binary +printing through papd. + +I've only been able to test these changes on a limited number of client +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/ + +Enjoy! + +Andy Morgan + diff --git a/config/papd.conf b/config/papd.conf index 09f453a0..c2c89c47 100644 --- a/config/papd.conf +++ b/config/papd.conf @@ -5,6 +5,10 @@ # pr str "lp" LPD printer name. # pa str "0.0" AppleTalk address (not usually needed). # op str "operator" Operator name, for LPD spooling. +# au flag not-present If present, authentication required +# am str none Comma separated list of uams to use +# (for every printer) whenever +# authentication is on # # Some examples: # @@ -17,4 +21,11 @@ # :pr=lp:op=wes:\ # :pd=/usr/share/lib/ppd/HPLJ_4M.PPD: # +# An example with authenticated printing: +# authprn:\ +# :pr=|/usr/bin/lpr -Plp:\ +# :pd=/usr/share/lib/ppd/HPLJ_4M.PPD:\ +# :au:\ +# :am=uams_clrtxt.so: +# # Note also that papd.conf can list several printers. diff --git a/etc/afpd/uam.c b/etc/afpd/uam.c index af39f358..c4e1f138 100644 --- a/etc/afpd/uam.c +++ b/etc/afpd/uam.c @@ -360,3 +360,9 @@ uam_afp_read_err: *buflen = 0; return len; } + +/* --- papd-specific functions (just placeholders) --- */ +void append(void *pf, char *data, int len) +{ + return; +} diff --git a/etc/atalkd/zip.c b/etc/atalkd/zip.c index 246fcb59..9012641e 100644 --- a/etc/atalkd/zip.c +++ b/etc/atalkd/zip.c @@ -596,13 +596,13 @@ int zip_packet( ap, from, data, len ) /* * Ignore ZIP GNIReplys which are either late or unsolicited. */ - syslog( LOG_INFO, "zip gnireply from %u.%u (%s %x)", + syslog( LOG_DEBUG, "zip gnireply from %u.%u (%s %x)", ntohs( from->sat_addr.s_net ), from->sat_addr.s_node, iface->i_name, iface->i_flags ); if (( iface->i_flags & ( IFACE_CONFIG|IFACE_PHASE1 )) || ( iface->i_flags & IFACE_ADDR ) == 0 ) { - syslog( LOG_INFO, "zip ignoring gnireply" ); + syslog( LOG_DEBUG, "zip ignoring gnireply" ); return 1; } diff --git a/etc/papd/Makefile b/etc/papd/Makefile index 64148d77..9957ddf2 100644 --- a/etc/papd/Makefile +++ b/etc/papd/Makefile @@ -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 auth.c uam.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 auth.o uam.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 @@ all : 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 showppd @@ -51,13 +61,18 @@ showppd: showppd.c ppd.c ${CC} ${CFLAGS} -DSHOWPPD -o showppd showppd.c ppd.c papd : ${OBJ} ../../libatalk/libatalk.a - ${CC} ${CFLAGS} ${LDFLAGS} -o papd ${OBJ} ${LIBDIRS} ${LIBS} + ${CC} ${CFLAGS} ${LDFLAGS_EXPORT} ${PAMINCPATH} ${PAMDEFS} \ + ${LDFLAGS} -o papd ${OBJ} ${LIBDIRS} ${LIBS} main.o : main.c ${CC} ${CFLAGS} -D_PATH_PAPDCONF=\"${ETCDIR}/papd.conf\" \ + -D_PATH_PAPDUAMPATH=\"${RESDIR}/uams/\" \ -DVERSION=\"`cat ../../VERSION`\" \ ${CPPFLAGS} -c main.c +queries.o : queries.c + ${CC} ${CFLAGS} ${PAMDEFS} -c queries.c + install : all ${INSTALL} -c papd ${SBINDIR} ${INSTALL} -c showppd ${BINDIR} diff --git a/etc/papd/auth.c b/etc/papd/auth.c new file mode 100644 index 00000000..90f41618 --- /dev/null +++ b/etc/papd/auth.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 1990,1993 Regents of The University of Michigan. + * All Rights Reserved. See COPYRIGHT. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uam_auth.h" + +static struct uam_mod uam_modules = {NULL, NULL, &uam_modules, &uam_modules}; +static struct uam_obj uam_login = {"", "", 0, {{NULL}}, &uam_login, + &uam_login}; +static struct uam_obj uam_changepw = {"", "", 0, {{NULL}}, &uam_changepw, + &uam_changepw}; +static struct uam_obj uam_printer = {"", "", 0, {{NULL}}, &uam_printer, + &uam_printer}; + + +/* + * Return a list of names for loaded uams + */ +int getuamnames(const int type, char *uamnames) +{ + struct uam_obj *prev, *start; + + if (!(start = UAM_LIST(type))) + return(-1); + + prev = start; + + while((prev = prev->uam_prev) != start) { + strcat(uamnames, prev->uam_name); + strcat(uamnames, "\n"); + } + + strcat(uamnames, "*\n"); + return(0); +} + + +/* just do a linked list search. this could be sped up with a hashed + * list, but i doubt anyone's going to have enough uams to matter. */ +struct uam_obj *auth_uamfind(const int type, const char *name, + const int len) +{ + struct uam_obj *prev, *start; + + if (!name || !(start = UAM_LIST(type))) + return NULL; + + prev = start; + while ((prev = prev->uam_prev) != start) + if (strndiacasecmp(prev->uam_name, name, len) == 0) + return prev; + + return NULL; +} + +int auth_register(const int type, struct uam_obj *uam) +{ + struct uam_obj *start; + + if (!uam || !uam->uam_name || (*uam->uam_name == '\0')) + return -1; + + if (!(start = UAM_LIST(type))) + return 0; /* silently fail */ + + uam_attach(start, uam); + return 0; +} + +/* load all of the modules */ +int auth_load(const char *path, const char *list) +{ + char name[MAXPATHLEN + 1], buf[MAXPATHLEN + 1], *p; + struct uam_mod *mod; + struct stat st; + int len; + + if (!path || !list || (len = strlen(path)) > sizeof(name) - 2) + return -1; + + strncpy(buf, list, sizeof(buf)); + if ((p = strtok(buf, ",")) == NULL) + return -1; + + strcpy(name, path); + if (name[len - 1] != '/') { + strcat(name, "/"); + len++; + } + + while (p) { + strncpy(name + len, p, sizeof(name) - len); + if ((stat(name, &st) == 0) && (mod = uam_load(name, p))) { + uam_attach(&uam_modules, mod); + syslog(LOG_INFO, "uam: %s loaded", p); + } + p = strtok(NULL, ","); + } +} + +/* get rid of all of the uams */ +void auth_unload() +{ + struct uam_mod *mod, *prev, *start = &uam_modules; + + prev = start->uam_prev; + while ((mod = prev) != start) { + prev = prev->uam_prev; + uam_detach(mod); + uam_unload(mod); + } +} diff --git a/etc/papd/file.c b/etc/papd/file.c index 63f08a06..5616d3e8 100644 --- a/etc/papd/file.c +++ b/etc/papd/file.c @@ -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 { + append( pf, "\n", 1 ); + } 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 ); - } -} + p = pf->pf_data + *linelength; -consumetomark( start, stop, pf ) - char *start, *stop; - struct papfile *pf; -{ - if ( start != pf->pf_cur || pf->pf_cur > stop || stop > pf->pf_end ) { - abort(); - } - - 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 @@ morespace( pf, data, len ) 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,16 +76,31 @@ morespace( pf, data, len ) 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; } + +append(pf, data, len) + struct papfile *pf; + char *data; + int len; +{ + if ((pf->pf_data + pf->pf_datalen + len) > + (pf->pf_buf + pf->pf_bufsize)) { + morespace(pf, data, len); + } else { + bcopy(data, pf->pf_data + pf->pf_datalen, len); + pf->pf_datalen += len; + } +} + + spoolerror( out, str ) struct papfile *out; char *str; @@ -110,7 +112,7 @@ spoolerror( out, str ) str = "Spooler error."; } - APPEND( out, pserr1, strlen( pserr1 )); - APPEND( out, str, strlen( str )); - APPEND( out, pserr2, strlen( pserr2 )); + append( out, pserr1, strlen( pserr1 )); + append( out, str, strlen( str )); + append( out, pserr2, strlen( pserr2 )); } diff --git a/etc/papd/file.h b/etc/papd/file.h index e6ae71e0..f33800d2 100644 --- a/etc/papd/file.h +++ b/etc/papd/file.h @@ -6,26 +6,22 @@ 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) #define PF_EOF (1<<1) #define PF_QUERY (1<<2) -#define APPEND( pf, data, len ) \ - if ( (pf)->pf_end + (len) > (pf)->pf_buf + (pf)->pf_len ) { \ - morespace( (pf), (data), (len)); \ - } else { \ - bcopy( (data), (pf)->pf_end, (len)); \ - (pf)->pf_end += (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); \ + if ((pf)->pf_datalen <= 0) { \ + (pf)->pf_data = (pf)->pf_buf; \ + (pf)->pf_datalen = 0; \ + } \ + } #define PF_MORESPACE 1024 diff --git a/etc/papd/headers.c b/etc/papd/headers.c index 12104bea..0b5dfc36 100644 --- a/etc/papd/headers.c +++ b/etc/papd/headers.c @@ -14,9 +14,10 @@ ch_title( in, out ) 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 @@ ch_title( in, out ) return( CH_MORE ); } + stop = start + linelength; for ( p = start; p < stop; p++ ) { if ( *p == ':' ) { break; @@ -50,10 +52,9 @@ ch_title( in, out ) *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 --git a/etc/papd/lp.c b/etc/papd/lp.c index be1e6c71..60ae548c 100644 --- a/etc/papd/lp.c +++ b/etc/papd/lp.c @@ -573,6 +573,7 @@ lp_queue( out ) struct papfile *out; { char buf[ 1024 ], *start, *stop, *p, *q; + int linelength, crlflength; static struct papfile pf; int n, len, s; @@ -591,19 +592,20 @@ lp_queue( out ) pf.pf_state = PF_BOT; while (( n = read( s, buf, sizeof( buf ))) > 0 ) { - APPEND( &pf, buf, n ); + append( &pf, buf, n ); } 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,15 +616,15 @@ lp_queue( out ) 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 ) && strncmp( kw_active, start, len ) == 0 ) || isdigit( *start )) { /* a job line */ - APPEND( out, tag_rank, strlen( tag_rank )); - APPEND( out, start, p - start ); - APPEND( out, "\n", 1 ); + append( out, tag_rank, strlen( tag_rank )); + append( out, start, p - start ); + append( out, "\n", 1 ); for ( ; p < stop; p++ ) { if ( *p != ' ' && *p != '\t' ) { @@ -635,13 +637,13 @@ lp_queue( out ) } } if ( p >= stop ) { - APPEND( out, ".\n", 2 ); - consumetomark( start, stop, &pf ); + append( out, ".\n", 2 ); + CONSUME( &pf, linelength + crlflength ); continue; } - APPEND( out, tag_owner, strlen( tag_owner )); - APPEND( out, q, p - q ); - APPEND( out, "\n", 1 ); + append( out, tag_owner, strlen( tag_owner )); + append( out, q, p - q ); + append( out, "\n", 1 ); for ( ; p < stop; p++ ) { if ( *p != ' ' && *p != '\t' ) { @@ -654,13 +656,13 @@ lp_queue( out ) } } if ( p >= stop ) { - APPEND( out, ".\n", 2 ); - consumetomark( start, stop, &pf ); + append( out, ".\n", 2 ); + CONSUME( &pf , linelength + crlflength ); continue; } - APPEND( out, tag_job, strlen( tag_job )); - APPEND( out, q, p - q ); - APPEND( out, "\n", 1 ); + append( out, tag_job, strlen( tag_job )); + append( out, q, p - q ); + append( out, "\n", 1 ); for ( ; p < stop; p++ ) { if ( *p != ' ' && *p != '\t' ) { @@ -683,35 +685,35 @@ lp_queue( out ) } } if ( p <= q ) { - APPEND( out, ".\n", 2 ); - consumetomark( start, stop, &pf ); + append( out, ".\n", 2 ); + CONSUME( &pf, linelength + crlflength ); continue; } - APPEND( out, tag_files, strlen( tag_files )); - APPEND( out, q, p - q ); - APPEND( out, "\n", 1 ); + append( out, tag_files, strlen( tag_files )); + append( out, q, p - q ); + append( out, "\n", 1 ); for ( ; p < stop; p++ ) { if ( *p != ' ' && *p != '\t' ) { break; } } - APPEND( out, tag_size, strlen( tag_size )); - APPEND( out, p, stop - p ); - APPEND( out, "\n.\n", 3 ); + append( out, tag_size, strlen( tag_size )); + 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, "\n.\n", 3 ); + append( out, tag_status, strlen( tag_status )); + append( out, start, linelength ); + append( out, "\n.\n", 3 ); - consumetomark( start, stop, &pf ); + CONSUME( &pf, linelength + crlflength ); } else { - APPEND( out, "*\n", 2 ); + append( out, "*\n", 2 ); lp_disconn_unix( s ); return( 0 ); } diff --git a/etc/papd/magics.c b/etc/papd/magics.c index dea2c009..b6d1ffe0 100644 --- a/etc/papd/magics.c +++ b/etc/papd/magics.c @@ -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 @@ ps( infile, outfile ) } } 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 @@ ps( infile, outfile ) } 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 @@ ps( infile, outfile ) } /* 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 @@ cm_psquery( in, out ) 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 @@ cm_psquery( in, out ) 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 @@ cm_psadobe( in, out ) 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 @@ cm_psswitch( in, out ) 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 @@ cm_psswitch( in, out ) return( CH_MORE ); } + stop = start + linelength; for ( p = start; p < stop; p++ ) { if ( *p == ' ' || *p == '\t' ) { break; diff --git a/etc/papd/main.c b/etc/papd/main.c index 4b2239b3..d9dc1aa1 100644 --- a/etc/papd/main.c +++ b/etc/papd/main.c @@ -51,10 +51,14 @@ struct printer *printer = NULL; char *version = VERSION; static char *pidfile = _PATH_PAPDLOCK; +char *uamlist; +char *uampath = _PATH_PAPDUAMPATH; + /* this only needs to be used by the server process */ static void papd_exit(const int i) { server_unlock(pidfile); + auth_unload(); exit(i); } @@ -236,6 +240,12 @@ main( ac, av ) pr->p_zone ); die( 1 ); } + if ( pr->p_flags & P_AUTH ) { + syslog( LOG_INFO, "Authentication enabled: %s", pr->p_name ); + } + else { + syslog( LOG_INFO, "Authentication disabled: %s", pr->p_name ); + } syslog( LOG_INFO, "register %s:%s@%s", pr->p_name, pr->p_type, pr->p_zone ); pr->p_flags |= P_REGISTERED; @@ -258,6 +268,11 @@ main( ac, av ) papd_exit( 1 ); } + /* + * Load UAMS + */ + auth_load(uampath, uamlist); + /* * Begin accepting connections. */ @@ -570,6 +585,23 @@ getprinters( cf ) strcpy( pr->p_printer, p ); } + /* + * Do we want authenticated printing? + */ + if ( pgetflag( "au", &a ) == 1 ) { + pr->p_flags |= P_AUTH; + } else { + pr->p_flags &= ~P_AUTH; + } + + if ((p = pgetstr("am", &a)) != NULL ) { + if ((uamlist = (char *)malloc(strlen(p)+1)) == NULL ) { + perror("malloc"); + exit(1); + } + strcpy(uamlist, p); + } + if ( pr->p_flags & P_SPOOLED ) { /* * Get operator name. @@ -714,9 +746,9 @@ rprintcap( pr ) * 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 --git a/etc/papd/printer.h b/etc/papd/printer.h index 72ce5b6c..f60e6612 100644 --- a/etc/papd/printer.h +++ b/etc/papd/printer.h @@ -50,6 +50,7 @@ struct printer { #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 --git a/etc/papd/queries.c b/etc/papd/queries.c index 28df0800..2d83b085 100644 --- a/etc/papd/queries.c +++ b/etc/papd/queries.c @@ -23,15 +23,17 @@ #include "comment.h" #include "printer.h" #include "ppd.h" +#include "uam_auth.h" cq_default( in, out ) 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 +41,19 @@ cq_default( in, out ) 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 +64,14 @@ cq_default( in, out ) 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 +84,15 @@ char *LoginFailed = "LoginFailed\n"; 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 +106,7 @@ cq_k4login( in, out ) } 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 )); @@ -111,9 +116,9 @@ cq_k4login( in, out ) if (( rc = krb_rd_req( &tkt, "LaserWriter", printer->p_name, 0, &ad, "" )) != RD_AP_OK ) { syslog( LOG_ERR, "cq_k4login: %s", krb_err_txt[ rc ] ); - APPEND( out, LoginFailed, strlen( LoginFailed )); + 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, @@ -121,9 +126,9 @@ cq_k4login( in, out ) lp_person( ad.pname ); lp_host( ad.prealm ); - APPEND( out, LoginOK, strlen( LoginOK )); + append( out, LoginOK, strlen( LoginOK )); compop(); - consumetomark( start, stop, in ); + CONSUME( in, linelength + crlflength); return( CH_DONE ); } @@ -132,11 +137,12 @@ char *uameth = "UMICHKerberosIV\n*\n"; 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 +151,7 @@ cq_uameth( in, out ) } 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 ); @@ -155,13 +161,13 @@ cq_uameth( in, out ) comsetflags( 1 ); } else { if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) { /* end */ - APPEND( out, uameth, strlen( uameth )); + append( out, uameth, strlen( uameth )); compop(); return( CH_DONE ); } } - consumetomark( start, stop, in ); + CONSUME( in, linelength + crlflength ); } } #endif KRB @@ -170,7 +176,7 @@ gq_true( out ) struct papfile *out; { if ( printer->p_flags & P_SPOOLED ) { - APPEND( out, "true\n", 5 ); + append( out, "true\n", 5 ); return( 0 ); } else { return( -1 ); @@ -184,18 +190,18 @@ gq_pagecost( out ) /* check for spooler? XXX */ if ( printer->p_pagecost_msg != NULL ) { - APPEND( out, printer->p_pagecost_msg, + append( out, printer->p_pagecost_msg, strlen( printer->p_pagecost_msg )); } else if ( printer->p_flags & P_ACCOUNT ) { #ifdef ABS_PRINT lp_pagecost(); #endif ABS_PRINT sprintf( cost, "%d", printer->p_pagecost ); - APPEND( out, cost, strlen( cost )); + append( out, cost, strlen( cost )); } else { return( -1 ); } - APPEND( out, "\n", 1 ); + append( out, "\n", 1 ); return( 0 ); } @@ -209,11 +215,53 @@ gq_balance( out ) return( -1 ); } sprintf( balance, "$%1.2f\n", printer->p_balance ); - APPEND( out, balance, strlen( balance )); + append( out, balance, strlen( balance )); return( 0 ); } #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); +} + + + +/* + * Handler for RBIUAMListQuery + */ + +static const char *nouams = "*\n"; + +gq_rbiuamlist( out ) + struct papfile *out; +{ + char uamnames[128] = "\0"; + + if (printer->p_flags & P_AUTH) { + if (getuamnames(UAM_SERVER_PRINTAUTH, uamnames) < 0) { + append(out, nouams, strlen(nouams)); + return(0); + } else { + append(out, uamnames, strlen(uamnames)); + return(0); + } + } else { + append(out, nouams, strlen(nouams)); + return(0); + } +} + + struct genquery { char *gq_name; int (*gq_handler)(); @@ -222,6 +270,8 @@ struct genquery { #ifdef notdef { "UMICHUserBalance", gq_balance }, #endif + { "RBISpoolerID", gq_rbispoolerid }, + { "RBIUAMListQuery", gq_rbiuamlist }, { "UMICHListQueue", gq_true }, { "UMICHDeleteJob", gq_true }, { NULL }, @@ -231,12 +281,13 @@ cq_query( in, out ) 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 +295,8 @@ cq_query( in, out ) return( CH_MORE ); } + stop = start+linelength; + if ( comgetflags() == 0 ) { /* started */ comsetflags( 1 ); @@ -282,12 +335,12 @@ cq_query( in, out ) } 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 ); } } @@ -313,14 +366,14 @@ cq_font_answer( start, stop, out ) if ( q != buf ) { *q = '\0'; - APPEND( out, "/", 1 ); - APPEND( out, buf, strlen( buf )); - APPEND( out, ":", 1 ); + append( out, "/", 1 ); + append( out, buf, strlen( buf )); + append( out, ":", 1 ); if (( pfo = ppd_font( buf )) == NULL ) { - APPEND( out, "No\n", 3 ); + append( out, "No\n", 3 ); } else { - APPEND( out, "Yes\n", 4 ); + append( out, "Yes\n", 4 ); } } } @@ -332,10 +385,11 @@ cq_font( in, out ) 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 +397,8 @@ cq_font( in, out ) return( CH_MORE ); } + stop = start + linelength; + if ( comgetflags() == 0 ) { comsetflags( 1 ); @@ -370,15 +426,15 @@ cq_font( in, out ) } else { comsetflags( 2 ); if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) { - APPEND( out, "*\n", 2 ); + 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 +442,12 @@ cq_feature( in, out ) 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 +455,8 @@ cq_feature( in, out ) return( CH_MORE ); } + stop = start + linelength; + if ( comgetflags() == 0 ) { comsetflags( 1 ); @@ -420,17 +479,17 @@ cq_feature( in, out ) return( CH_DONE ); } - APPEND( out, pfe->pd_value, strlen( pfe->pd_value )); - APPEND( out, "\r", 1 ); + append( out, pfe->pd_value, strlen( pfe->pd_value )); + append( out, "\r", 1 ); } 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 +499,13 @@ static const char *prod = "*Product\n"; cq_printer( in, out ) struct papfile *in, *out; { - char *start, *stop, *p; - struct comment *c, *comment = compeek(); + char *start, *p; + int linelength, crlflength; + struct comment *comment = compeek(); struct ppd_feature *pdpsver, *pdprod; for (;;) { - switch ( markline( &start, &stop, in )) { + switch ( markline( in, &start, &linelength, &crlflength )) { case 0 : return( 0 ); @@ -487,25 +547,25 @@ cq_printer( in, out ) } /* revision */ - APPEND( out, p + 1, strlen( p + 1 )); - APPEND( out, "\r", 1 ); + append( out, p + 1, strlen( p + 1 )); + append( out, "\r", 1 ); /* version */ - APPEND( out, pdpsver->pd_value, p - pdpsver->pd_value ); - APPEND( out, "\r", 1 ); + append( out, pdpsver->pd_value, p - pdpsver->pd_value ); + append( out, "\r", 1 ); /* product */ - APPEND( out, pdprod->pd_value, strlen( pdprod->pd_value )); - APPEND( out, "\r", 1 ); + 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 +576,10 @@ cq_rmjob( in, out ) 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 +587,8 @@ cq_rmjob( in, out ) return( CH_MORE ); } + stop = start + linelength; + for ( p = start; p < stop; p++ ) { if ( *p == ' ' || *p == '\t' ) { break; @@ -540,22 +603,23 @@ cq_rmjob( in, out ) *stop = '\0'; if ( p < stop && ( job = atoi( p )) > 0 ) { lp_rmjob( job ); - APPEND( out, rmjobok, strlen( rmjobok )); + append( out, rmjobok, strlen( rmjobok )); } else { - APPEND( out, rmjobfailed, strlen( rmjobfailed )); + append( out, rmjobfailed, strlen( rmjobfailed )); } 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 +632,79 @@ cq_listq( in, out ) } compop(); - consumetomark( start, stop, in ); + CONSUME( in, linelength + crlflength ); return( CH_DONE ); } + +/* + * Handler for RBILogin + */ + +static struct uam_obj *papd_uam = NULL; +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, *begin; + int linelength, crlflength; + char username[9] = "\0"; + struct comment *comment = compeek(); + char uamtype[20] = "\0"; + + for (;;) { + switch ( markline( in, &start, &linelength, &crlflength )) { + case 0 : + return( 0 ); + + case -1 : + return( CH_MORE ); + } + + stop = start + linelength; + + if ( comgetflags() == 0 ) { /* first line */ + begin = start + strlen(comment->c_begin); + p = begin; + + while (*p != ' ') { + p++; + } + + strncat(uamtype, begin, p - begin); + + if ((papd_uam = auth_uamfind(UAM_SERVER_PRINTAUTH, + uamtype, strlen(uamtype))) == NULL) { + syslog(LOG_INFO, "Could not find uam: %s", uamtype); + append(out, rbiloginbad, strlen(rbiloginbad)); + append(out, rbiloginerrstr, strlen(rbiloginerrstr)); + } else { + if ( (papd_uam->u.uam_printer(p,stop,username,out)) == 0 ) { + lp_person( username ); + } else { + 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 ); + } +} + + /* * All queries start with %%?Begin and end with %%?End. Note that the * "Begin"/"End" general queries have to be last. @@ -583,6 +716,7 @@ struct comment queries[] = { #endif KRB { "%UMICHListQueue", 0, cq_listq, C_FULL }, { "%UMICHDeleteJob", 0, cq_rmjob, 0 }, + { "%%?BeginQuery: RBILogin ", "%%?EndQuery", cq_rbilogin, 0 }, { "%%?BeginQuery", "%%?EndQuery", cq_query, 0 }, { "%%?BeginFeatureQuery", "%%?EndFeatureQuery", cq_feature, 0 }, { "%%?BeginFontQuery", "%%?EndFontQuery", cq_font, 0 }, diff --git a/etc/papd/session.c b/etc/papd/session.c index c58ac9a7..4d73255d 100644 --- a/etc/papd/session.c +++ b/etc/papd/session.c @@ -59,16 +59,16 @@ session( atp, sat ) 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 @@ session( atp, sat ) * 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 { @@ -219,7 +219,7 @@ session( atp, sat ) } for ( i = 0; i < atpb.atp_rresiovcnt; i++ ) { - APPEND( &infile, + append( &infile, niov[ i ].iov_base + 4, niov[ i ].iov_len - 4 ); if (( infile.pf_state & PF_EOF ) == 0 && ((char *)niov[ 0 ].iov_base)[ 2 ] ) { @@ -262,17 +262,17 @@ session( atp, sat ) /* 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 @@ session( atp, sat ) } 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; } diff --git a/etc/papd/uam.c b/etc/papd/uam.c new file mode 100644 index 00000000..a7ca13a1 --- /dev/null +++ b/etc/papd/uam.c @@ -0,0 +1,225 @@ +/* Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu) + * All Rights Reserved. See COPYRIGHT. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "uam_auth.h" + +/* --- server uam functions -- */ + +/* uam_load. uams must have a uam_setup function. */ +struct uam_mod *uam_load(const char *path, const char *name) +{ + char buf[MAXPATHLEN + 1], *p; + struct uam_mod *mod; + void *module; + + if ((module = mod_open(path)) == NULL) { + syslog(LOG_ERR, "uam_load(%s): failed to load.", name); + syslog(LOG_ERR, dlerror()); + return NULL; + } + + if ((mod = (struct uam_mod *) malloc(sizeof(struct uam_mod))) == NULL) { + syslog(LOG_ERR, "uam_load(%s): malloc failed", name); + goto uam_load_fail; + } + + strncpy(buf, name, sizeof(buf)); + if ((p = strchr(buf, '.'))) + *p = '\0'; + if ((mod->uam_fcn = mod_symbol(module, buf)) == NULL) { + goto uam_load_err; + } + + if (mod->uam_fcn->uam_type != UAM_MODULE_SERVER) { + syslog(LOG_ERR, "uam_load(%s): attempted to load a non-server module", + name); + goto uam_load_err; + } + + /* version check would go here */ + + if (!mod->uam_fcn->uam_setup || + ((*mod->uam_fcn->uam_setup)(name) < 0)) { + syslog(LOG_ERR, "uam_load(%s): uam_setup failed", name); + goto uam_load_err; + } + + mod->uam_module = module; + return mod; + +uam_load_err: + free(mod); +uam_load_fail: + mod_close(module); + return NULL; +} + +/* unload the module. we check for a cleanup function, but we don't + * die if one doesn't exist. however, things are likely to leak without one. + */ +void uam_unload(struct uam_mod *mod) +{ + if (mod->uam_fcn->uam_cleanup) + (*mod->uam_fcn->uam_cleanup)(); + mod_close(mod->uam_module); + free(mod); +} + +/* -- client-side uam functions -- */ + +/* set up stuff for this uam. */ +int uam_register(const int type, const char *path, const char *name, ...) +{ + va_list ap; + struct uam_obj *uam; + + if (!name) + return -1; + + /* see if it already exists. */ + if ((uam = auth_uamfind(type, name, strlen(name)))) { + if (strcmp(uam->uam_path, path)) { + /* it exists, but it's not the same module. */ + syslog(LOG_ERR, "uam_register: \"%s\" already loaded by %s", + name, path); + return -1; + } + uam->uam_count++; + return 0; + } + + /* allocate space for uam */ + if ((uam = calloc(1, sizeof(struct uam_obj))) == NULL) + return -1; + + uam->uam_name = name; + uam->uam_path = strdup(path); + uam->uam_count++; + + va_start(ap, name); + switch (type) { + case UAM_SERVER_LOGIN: /* expect three arguments */ + uam->u.uam_login.login = va_arg(ap, void *); + uam->u.uam_login.logincont = va_arg(ap, void *); + uam->u.uam_login.logout = va_arg(ap, void *); + break; + case UAM_SERVER_CHANGEPW: /* one argument */ + uam->u.uam_changepw = va_arg(ap, void *); + break; + case UAM_SERVER_PRINTAUTH: /* x arguments */ + uam->u.uam_printer = va_arg(ap, void *); + break; + default: + break; + } + va_end(ap); + + /* attach to other uams */ + if (auth_register(type, uam) < 0) { + free(uam->uam_path); + free(uam); + return -1; + } + + return 0; +} + +void uam_unregister(const int type, const char *name) +{ + struct uam_obj *uam; + + if (!name) + return; + + uam = auth_uamfind(type, name, strlen(name)); + if (!uam || --uam->uam_count > 0) + return; + + auth_unregister(uam); + free(uam->uam_path); + free(uam); +} + +/* Crap to support uams which call this afpd function */ +int uam_afpserver_option(void *private, const int what, void *option, + int *len) +{ + return(0); +} + +/* --- helper functions for plugin uams --- */ + +struct passwd *uam_getname(char *name, const int len) +{ + struct passwd *pwent; + char *user; + int i; + + if ((pwent = getpwnam(name))) + return pwent; + +#ifndef NO_REAL_USER_NAME + for (i = 0; i < len; i++) + name[i] = tolower(name[i]); + + setpwent(); + while ((pwent = getpwent())) { + if (user = strchr(pwent->pw_gecos, ',')) + *user = '\0'; + user = pwent->pw_gecos; + + /* check against both the gecos and the name fields. the user + * might have just used a different capitalization. */ + if ((strncasecmp(user, name, len) == 0) || + (strncasecmp(pwent->pw_name, name, len) == 0)) { + strncpy(name, pwent->pw_name, len); + break; + } + } + endpwent(); +#endif + + /* os x server doesn't keep anything useful if we do getpwent */ + return pwent ? getpwnam(name) : NULL; +} + + +int uam_checkuser(const struct passwd *pwd) +{ + char *p; + + if (!pwd || !pwd->pw_shell || (*pwd->pw_shell == '\0')) + return -1; + + while ((p = getusershell())) { + if ( strcmp( p, pwd->pw_shell ) == 0 ) + break; + } + endusershell(); + + if (!p) { + syslog( LOG_INFO, "illegal shell %s for %s",pwd->pw_shell,pwd->pw_name); + return -1; + } + + return 0; +} + + diff --git a/etc/papd/uam_auth.h b/etc/papd/uam_auth.h new file mode 100644 index 00000000..bf644fc5 --- /dev/null +++ b/etc/papd/uam_auth.h @@ -0,0 +1,67 @@ +/* Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu) + * All Rights Reserved. See COPYRIGHT. + * + * interface between uam.c and auth.c + */ + +#ifndef PAPD_UAM_AUTH_H +#define PAPD_UAM_AUTH_H 1 + +#include +#include + +#include + +struct uam_mod { + void *uam_module; + struct uam_export *uam_fcn; + struct uam_mod *uam_prev, *uam_next; +}; + +struct uam_obj { + const char *uam_name; /* authentication method */ + char *uam_path; /* where it's located */ + int uam_count; + union { + struct { + int (*login) __P((void *, struct passwd **, + char *, int, char *, int *)); + int (*logincont) __P((void *, struct passwd **, char *, + int, char *, int *)); + void (*logout) __P((void)); + } uam_login; + int (*uam_changepw) __P((void *, char *, struct passwd *, char *, + int, char *, int *)); + int (*uam_printer) __P((char *, char *, char *, struct papfile *)); + } u; + struct uam_obj *uam_prev, *uam_next; +}; + +#define uam_attach(a, b) do { \ + (a)->uam_prev->uam_next = (b); \ + (b)->uam_prev = (a)->uam_prev; \ + (b)->uam_next = (a); \ + (a)->uam_prev = (b); \ +} while (0) + +#define uam_detach(a) do { \ + (a)->uam_prev->uam_next = (a)->uam_next; \ + (a)->uam_next->uam_prev = (a)->uam_prev; \ +} while (0) + +#define UAM_LIST(type) (((type) == UAM_SERVER_LOGIN) ? &uam_login : \ + (((type) == UAM_SERVER_CHANGEPW) ? &uam_changepw : \ + (((type) == UAM_SERVER_PRINTAUTH) ? &uam_printer : NULL))) + + +extern struct uam_mod *uam_load __P((const char *, const char *)); +extern void uam_unload __P((struct uam_mod *)); + +/* auth.c */ +int auth_load __P((const char *, const char *)); +int auth_register __P((const int, struct uam_obj *)); +#define auth_unregister(a) uam_detach(a) +struct uam_obj *auth_uamfind __P((const int, const char *, const int)); +void auth_unload __P((void)); + +#endif /* uam_auth.h */ diff --git a/etc/uams/uams_guest.c b/etc/uams/uams_guest.c index 41e2d70b..0fe9d5cb 100644 --- a/etc/uams/uams_guest.c +++ b/etc/uams/uams_guest.c @@ -42,13 +42,60 @@ static int noauth_login(void *obj, struct passwd **uam_pwd, return( AFP_OK ); } + +/* Printer NoAuthUAM Login */ +int noauth_printer(start, stop, username, out) + char *start, *stop, *username; + struct papfile *out; +{ + char *data, *p, *q; + static const char *loginok = "0\r"; + + data = (char *)malloc(stop - start + 1); + strncpy(data, start, stop - start + 1); + + /* We are looking for the following format in data: + * (username) + * + * Hopefully username doesn't contain a ")" + */ + + if ((p = strchr(data, '(' )) == NULL) { + syslog(LOG_INFO,"Bad Login NoAuthUAM: username not found in string"); + free(data); + return(-1); + } + p++; + if ((q = strchr(data, ')' )) == NULL) { + syslog(LOG_INFO,"Bad Login NoAuthUAM: username not found in string"); + free(data); + return(-1); + } + strncpy(username, p, q - p); + + /* Done copying username, clean up */ + free(data); + + if (getpwnam(username) == NULL) { + syslog(LOG_INFO, "Bad Login NoAuthUAM: %s: %m", username); + return(-1); + } + + /* Login successful */ + append(out, loginok, strlen(loginok)); + syslog(LOG_INFO, "Login NoAuthUAM: %s", username); + return(0); +} + + static int uam_setup(const char *path) { if (uam_register(UAM_SERVER_LOGIN, path, "No User Authent", noauth_login, NULL, NULL) < 0) - return -1; - /* uam_register(UAM_SERVER_PRINTAUTH, path, - "No User Authent", noauth_printer); */ + return -1; + if (uam_register(UAM_SERVER_PRINTAUTH, path, "NoAuthUAM", + noauth_printer) < 0) + return -1; return 0; } @@ -56,7 +103,7 @@ static int uam_setup(const char *path) static void uam_cleanup() { uam_unregister(UAM_SERVER_LOGIN, "No User Authent"); - /* uam_unregister(UAM_SERVER_PRINTAUTH, "No User Authent"); */ + uam_unregister(UAM_SERVER_PRINTAUTH, "NoAuthUAM"); } UAM_MODULE_EXPORT struct uam_export uams_guest = { diff --git a/etc/uams/uams_pam.c b/etc/uams/uams_pam.c index 3475913f..7b950b24 100644 --- a/etc/uams/uams_pam.c +++ b/etc/uams/uams_pam.c @@ -255,20 +255,121 @@ static int pam_changepw(void *obj, char *username, } +/* Printer ClearTxtUAM login */ +int pam_printer(start, stop, username, out) + char *start, *stop, *username; + struct papfile *out; +{ + int PAM_error; + char *data, *p, *q; + char password[PASSWDLEN + 1] = "\0"; + static const char *loginok = "0\r"; + + data = (char *)malloc(stop - start + 1); + strncpy(data, start, stop - start + 1); + + /* We are looking for the following format in data: + * (username) (password) + * + * Let's hope username doesn't contain ") ("! + */ + + /* Parse input for username in () */ + if ((p = strchr(data, '(' )) == NULL) { + syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string"); + free(data); + return(-1); + } + p++; + if ((q = strstr(data, ") (" )) == NULL) { + syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string"); + free(data); + return(-1); + } + strncpy(username, p, q - p); + + /* Parse input for password in next () */ + p = q + 3; + if ((q = strrchr(data, ')' )) == NULL) { + syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string"); + free(data); + return(-1); + } + strncpy(password, p, q - p); + + /* Done copying username and password, clean up */ + free(data); + + PAM_username = username; + PAM_password = password; + + PAM_error = pam_start("netatalk", username, &PAM_conversation, + &pamh); + if (PAM_error != PAM_SUCCESS) { + syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s", + username, pam_strerror(pamh, PAM_error)); + 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) { + syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s", + username, pam_strerror(pamh, PAM_error)); + pam_end(pamh, PAM_error); + pamh = NULL; + return(-1); + } + + PAM_error = pam_acct_mgmt(pamh, 0); + if (PAM_error != PAM_SUCCESS) { + syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s", + username, pam_strerror(pamh, PAM_error)); + pam_end(pamh, PAM_error); + pamh = NULL; + return(-1); + } + + PAM_error = pam_open_session(pamh, 0); + if (PAM_error != PAM_SUCCESS) { + syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: %s", + username, pam_strerror(pamh, PAM_error)); + pam_end(pamh, PAM_error); + pamh = NULL; + return(-1); + } + + /* Login successful, but no need to hang onto it, + so logout immediately */ + append(out, loginok, strlen(loginok)); + syslog(LOG_INFO, "Login ClearTxtUAM: %s", username); + pam_close_session(pamh, 0); + pam_end(pamh, 0); + pamh = NULL; + + return(0); +} + + static int uam_setup(const char *path) { if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd", pam_login, NULL, pam_logout) < 0) - return -1; + return -1; if (uam_register(UAM_SERVER_CHANGEPW, path, "Cleartxt Passwrd", pam_changepw) < 0) { - uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd"); - return -1; + uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd"); + return -1; } - /*uam_register(UAM_SERVER_PRINTAUTH, path, "Cleartxt Passwrd", - pam_printer);*/ + if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM", + pam_printer) < 0) { + return -1; + } return 0; } @@ -277,7 +378,7 @@ static void uam_cleanup(void) { uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd"); uam_unregister(UAM_SERVER_CHANGEPW, "Cleartxt Passwrd"); - /*uam_unregister(UAM_SERVER_PRINTAUTH, "Cleartxt Passwrd"); */ + uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM"); } UAM_MODULE_EXPORT struct uam_export uams_clrtxt = { diff --git a/etc/uams/uams_passwd.c b/etc/uams/uams_passwd.c index 67699a97..3d97959b 100644 --- a/etc/uams/uams_passwd.c +++ b/etc/uams/uams_passwd.c @@ -130,20 +130,118 @@ static int passwd_changepw(void *obj, char *username, } #endif + +/* Printer ClearTxtUAM login */ +static int passwd_printer(start, stop, username, out) + char *start, *stop, *username; + struct papfile *out; +{ + struct passwd *pwd; +#ifdef SHADOWPW + struct spwd *sp; +#endif + char *data, *p, *q; + char password[PASSWDLEN + 1] = "\0"; + static const char *loginok = "0\r"; + int ulen; + + data = (char *)malloc(stop - start + 1); + strncpy(data, start, stop - start + 1); + + /* We are looking for the following format in data: + * (username) (password) + * + * Let's hope username doesn't contain ") ("! + */ + + /* Parse input for username in () */ + if ((p = strchr(data, '(' )) == NULL) { + syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string"); + free(data); + return(-1); + } + p++; + if ((q = strstr(data, ") (" )) == NULL) { + syslog(LOG_INFO,"Bad Login ClearTxtUAM: username not found in string"); + free(data); + return(-1); + } + strncpy(username, p, q - p); + + /* Parse input for password in next () */ + p = q + 3; + if ((q = strrchr(data, ')' )) == NULL) { + syslog(LOG_INFO,"Bad Login ClearTxtUAM: password not found in string"); + free(data); + return(-1); + } + strncpy(password, p, q - p); + + /* Done copying username and password, clean up */ + free(data); + + ulen = strlen(username); + + if (( pwd = uam_getname(username, ulen)) == NULL ) { + syslog(LOG_INFO, "Bad Login ClearTxtUAM: ( %s ) not found ", + username); + return(-1); + } + + if (uam_checkuser(pwd) < 0) { + /* syslog of error happens in uam_checkuser */ + return(-1); + } + +#ifdef SHADOWPW + if (( sp = getspnam( pwd->pw_name )) == NULL ) { + syslog(LOG_INFO, "Bad Login ClearTxtUAM: no shadow passwd entry for %s", + username); + return(-1); + } + pwd->pw_passwd = sp->sp_pwdp; +#endif SHADOWPW + + if (!pwd->pw_passwd) { + syslog(LOG_INFO, "Bad Login ClearTxtUAM: no password for %s", + username); + return(-1); + } + +#ifdef AFS + if ( kcheckuser( pwd, password) == 0) + return(0); +#endif AFS + + p = crypt(password, pwd->pw_passwd); + if (strcmp(p, pwd->pw_passwd) != 0) { + syslog(LOG_INFO, "Bad Login ClearTxtUAM: %s: bad password", username); + return(-1); + } + + /* Login successful */ + append(out, loginok, strlen(loginok)); + syslog(LOG_INFO, "Login ClearTxtUAM: %s", username); + return(0); +} + + static int uam_setup(const char *path) { - if (uam_register(UAM_SERVER_LOGIN, path, - "Cleartxt Passwrd", passwd_login, NULL, NULL) < 0) - return -1; - /*uam_register(UAM_SERVER_PRINTAUTH, path, "Cleartxt Passwrd", - passwd_printer);*/ + if (uam_register(UAM_SERVER_LOGIN, path, "Cleartxt Passwrd", + passwd_login, NULL, NULL) < 0) + return -1; + if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM", + passwd_printer) < 0) + return -1; + return 0; } static void uam_cleanup(void) { uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd"); - /*uam_unregister(UAM_SERVER_PRINTAUTH, "Cleartxt Passwrd"); */ + uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM"); } UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {