2 * Copyright (c) 1990,1994 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
6 * Copyright (c) 1983 Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * Interface to lpr system.
46 #include <sys/param.h>
47 #include <sys/syslog.h>
49 #include <sys/socket.h>
51 #if defined( sun ) && defined( __svr4__ )
52 #include </usr/ucbinclude/sys/file.h>
57 #include <netinet/in.h>
59 #include <netatalk/at.h>
60 #include <atalk/atp.h>
61 #include <atalk/paths.h>
77 char hostname[ MAXHOSTNAMELEN ];
79 extern struct sockaddr_at *sat;
81 /* initialize printing interface */
83 /* cancel current job */
85 /* print current job */
88 /* open a file for spooling */
90 /* open a buffer to the current open file */
92 /* close current spooling file */
104 #define LP_INIT (1<<0)
105 #define LP_OPEN (1<<1)
106 #define LP_PIPE (1<<2)
107 #define LP_CONNECT (1<<3)
108 #define LP_QUEUE (1<<4)
113 if ( lp.lp_person != NULL ) {
114 free( lp.lp_person );
116 if (( lp.lp_person = (char *)malloc( strlen( person ) + 1 )) == NULL ) {
117 syslog( LOG_ERR, "malloc: %m" );
120 strcpy( lp.lp_person, person );
130 if ( lp.lp_person == NULL ) {
133 err = ABS_canprint( lp.lp_person, printer->p_role, printer->p_srvid,
135 printer->p_pagecost = floor( atof( cost ) * 10000.0 );
136 printer->p_balance = atof( balance ) + atof( cost );
137 return( err < 0 ? -1 : 0 );
144 if ( lp.lp_host != NULL ) {
147 if (( lp.lp_host = (char *)malloc( strlen( host ) + 1 )) == NULL ) {
148 syslog( LOG_ERR, "malloc: %m" );
151 strcpy( lp.lp_host, host );
159 if ( lp.lp_job != NULL ) {
162 if (( lp.lp_job = (char *)malloc( strlen( job ) + 1 )) == NULL ) {
163 syslog( LOG_ERR, "malloc: %m" );
166 for ( p = job, q = lp.lp_job; *p != '\0'; p++, q++ ) {
167 if ( !isascii( *p ) || !isprint( *p ) || *p == '\\' ) {
178 struct sockaddr_at *sat;
181 char *cp, buf[ BUFSIZ ];
183 int authenticated = 0;
188 #if defined( CAPDIR ) || defined( USE_CAP )
190 int addr_net, addr_node;
193 char addr_filename[256];
196 if ( printer->p_flags & P_AUTH ) {
199 if ( printer->p_flags & P_AUTH_CAP ) {
200 addr_net = ntohs( sat->sat_addr.s_net );
201 addr_node = sat->sat_addr.s_node;
202 sprintf(addr_filename, "%s/net%d.%dnode%d", CAPDIR, addr_net/256, addr_net%256, addr_node);
203 if (stat(addr_filename, &cap_st) == 0) {
204 if ((cap_file = fopen(addr_filename, "r")) != NULL) {
205 if (fscanf(cap_file, "%s", username) != EOF) {
206 if (getpwnam(username) != NULL ) {
207 syslog(LOG_INFO, "CAP authenticated %s", username);
211 syslog(LOG_INFO, "CAP error: invalid username: '%s'", username);
214 syslog(LOG_INFO, "CAP error: could not read username");
217 syslog(LOG_INFO, "CAP error: %m");
220 syslog(LOG_INFO, "CAP error: %m");
225 if ( printer->p_flags & P_AUTH_PSSP ) {
226 if ( lp.lp_person != NULL ) {
231 if ( authenticated == 0 ) {
232 syslog( LOG_ERR, "lp_init: must authenticate" );
233 spoolerror( out, "Authentication required." );
238 if (( printer->p_flags & P_ACCOUNT ) && printer->p_pagecost > 0 &&
239 ! ABS_canprint( lp.lp_person, printer->p_role,
240 printer->p_srvid, cost, balance )) {
241 syslog( LOG_ERR, "lp_init: no ABS funds" );
242 spoolerror( out, "No ABS funds available." );
248 if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
249 syslog( LOG_ERR, "gethostname: %m" );
253 if ( lp.lp_flags & LP_INIT ) {
254 syslog( LOG_ERR, "lp_init: already inited, die!" );
262 if ( printer->p_flags & P_SPOOLED ) {
263 /* check if queuing is enabled: mode & 010 on lock file */
264 if ( stat( printer->p_lock, &st ) < 0 ) {
265 syslog( LOG_ERR, "lp_init: %s: %m", printer->p_lock );
266 spoolerror( out, NULL );
269 if ( st.st_mode & 010 ) {
270 syslog( LOG_INFO, "lp_init: queuing is disabled" );
271 spoolerror( out, "Queuing is disabled." );
275 if (( fd = open( ".seq", O_RDWR|O_CREAT, 0661 )) < 0 ) {
276 syslog( LOG_ERR, "lp_init: can't create .seq" );
277 spoolerror( out, NULL );
281 if ( flock( fd, LOCK_EX ) < 0 ) {
282 syslog( LOG_ERR, "lp_init: can't lock .seq" );
283 spoolerror( out, NULL );
288 if (( len = read( fd, buf, sizeof( buf ))) < 0 ) {
289 syslog( LOG_ERR, "lp_init read: %m" );
290 spoolerror( out, NULL );
294 for ( cp = buf; len; len--, cp++ ) {
295 if ( *cp < '0' || *cp > '9' ) {
298 n = n * 10 + ( *cp - '0' );
303 n = ( n + 1 ) % 1000;
304 sprintf( buf, "%03d\n", n );
306 write( fd, buf, strlen( buf ));
309 lp.lp_flags |= LP_PIPE;
310 lp.lp_seq = getpid();
313 lp.lp_flags |= LP_INIT;
319 struct sockaddr_at *sat;
321 char name[ MAXPATHLEN ];
323 struct passwd *pwent;
325 if (( lp.lp_flags & LP_INIT ) == 0 && lp_init( out, sat ) != 0 ) {
328 if ( lp.lp_flags & LP_OPEN ) {
329 syslog( LOG_ERR, "lp_open already open" );
333 if ( lp.lp_flags & LP_PIPE ) {
334 /* go right to program */
335 if (lp.lp_person != NULL) {
336 if((pwent = getpwnam(lp.lp_person)) != NULL) {
337 if(setreuid(pwent->pw_uid, pwent->pw_uid) != 0) {
338 syslog(LOG_INFO, "setreuid error: %m");
341 syslog(LOG_INFO, "Error getting username (%s)", lp.lp_person);
344 if (( lp.lp_stream = popen( printer->p_printer, "w" )) == NULL ) {
345 syslog( LOG_ERR, "lp_open popen %s: %m", printer->p_printer );
346 spoolerror( out, NULL );
350 sprintf( name, "df%c%03d%s", lp.lp_letter++, lp.lp_seq, hostname );
352 if (( fd = open( name, O_WRONLY|O_CREAT|O_EXCL, 0660 )) < 0 ) {
353 syslog( LOG_ERR, "lp_open %s: %m", name );
354 spoolerror( out, NULL );
357 if (( lp.lp_stream = fdopen( fd, "w" )) == NULL ) {
358 syslog( LOG_ERR, "lp_open fdopen: %m" );
359 spoolerror( out, NULL );
363 lp.lp_flags |= LP_OPEN;
370 if (( lp.lp_flags & LP_INIT ) == 0 || ( lp.lp_flags & LP_OPEN ) == 0 ) {
373 fclose( lp.lp_stream );
375 lp.lp_flags &= ~LP_OPEN;
383 if (( lp.lp_flags & LP_OPEN ) == 0 ) {
387 if ( fwrite( buf, 1, len, lp.lp_stream ) != len ) {
388 syslog( LOG_ERR, "lp_write: %m" );
396 char name[ MAXPATHLEN ];
399 if (( lp.lp_flags & LP_INIT ) == 0 || lp.lp_letter == 'A' ) {
403 if ( lp.lp_flags & LP_OPEN ) {
407 for ( letter = 'A'; letter < lp.lp_letter; letter++ ) {
408 sprintf( name, "df%c%03d%s", letter, lp.lp_seq, hostname );
409 if ( unlink( name ) < 0 ) {
410 syslog( LOG_ERR, "lp_cancel unlink %s: %m", name );
418 * Create printcap control file, signal printer. Errors here should
419 * remove queue files.
425 char buf[ MAXPATHLEN ];
426 char tfname[ MAXPATHLEN ];
427 char cfname[ MAXPATHLEN ];
432 if (( lp.lp_flags & LP_INIT ) == 0 || lp.lp_letter == 'A' ) {
437 if ( printer->p_flags & P_SPOOLED ) {
438 sprintf( tfname, "tfA%03d%s", lp.lp_seq, hostname );
439 if (( fd = open( tfname, O_WRONLY|O_EXCL|O_CREAT, 0660 )) < 0 ) {
440 syslog( LOG_ERR, "lp_print %s: %m", tfname );
443 if (( cfile = fdopen( fd, "w" )) == NULL ) {
444 syslog( LOG_ERR, "lp_print %s: %m", tfname );
447 fprintf( cfile, "H%s\n", hostname ); /* XXX lp_host? */
449 if ( lp.lp_person ) {
450 fprintf( cfile, "P%s\n", lp.lp_person );
452 fprintf( cfile, "P%s\n", printer->p_operator );
455 if ( lp.lp_job && *lp.lp_job ) {
456 fprintf( cfile, "J%s\n", lp.lp_job );
457 fprintf( cfile, "T%s\n", lp.lp_job );
459 fprintf( cfile, "JMac Job\n" );
460 fprintf( cfile, "TMac Job\n" );
463 fprintf( cfile, "C%s\n", hostname ); /* XXX lp_host? */
465 if ( lp.lp_person ) {
466 fprintf( cfile, "L%s\n", lp.lp_person );
468 fprintf( cfile, "L%s\n", printer->p_operator );
471 for ( letter = 'A'; letter < lp.lp_letter; letter++ ) {
472 fprintf( cfile, "fdf%c%03d%s\n", letter, lp.lp_seq, hostname );
473 fprintf( cfile, "Udf%c%03d%s\n", letter, lp.lp_seq, hostname );
476 if ( lp.lp_job && *lp.lp_job ) {
477 fprintf( cfile, "N%s\n", lp.lp_job );
479 fprintf( cfile, "NMac Job\n" );
483 sprintf( cfname, "cfA%03d%s", lp.lp_seq, hostname );
484 if ( link( tfname, cfname ) < 0 ) {
485 syslog( LOG_ERR, "lp_print can't link %s to %s: %m", cfname,
491 if (( s = lp_conn_unix()) < 0 ) {
492 syslog( LOG_ERR, "lp_print: lp_conn_unix: %m" );
496 sprintf( buf, "\1%s\n", printer->p_printer );
498 if ( write( s, buf, n ) != n ) {
499 syslog( LOG_ERR, "lp_print write: %m" );
502 if ( read( s, buf, 1 ) != 1 ) {
503 syslog( LOG_ERR, "lp_print read: %m" );
507 lp_disconn_unix( s );
509 if ( buf[ 0 ] != '\0' ) {
510 syslog( LOG_ERR, "lp_print lpd said %c: %m", buf[ 0 ] );
514 syslog( LOG_INFO, "lp_print queued" );
518 lp_disconn_unix( fd )
520 return( close( fd ));
526 struct sockaddr_un saun;
528 if (( s = socket( AF_UNIX, SOCK_STREAM, 0 )) < 0 ) {
529 syslog( LOG_ERR, "lp_conn_unix socket: %m" );
532 bzero( &saun, sizeof( struct sockaddr_un ));
533 saun.sun_family = AF_UNIX;
534 strcpy( saun.sun_path, _PATH_DEVPRINTER );
535 if ( connect( s, (struct sockaddr *)&saun,
536 strlen( saun.sun_path ) + 2 ) < 0 ) {
537 syslog( LOG_ERR, "lp_conn_unix connect %s: %m", saun.sun_path );
545 lp_disconn_inet( fd )
547 return( close( fd ));
552 int privfd, port = IPPORT_RESERVED - 1;
553 struct sockaddr_in sin;
557 if (( sp = getservbyname( "printer", "tcp" )) == NULL ) {
558 syslog( LOG_ERR, "printer/tcp: unknown service\n" );
562 if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
563 syslog( LOG_ERR, "gethostname: %m" );
567 if (( hp = gethostbyname( hostname )) == NULL ) {
568 syslog( LOG_ERR, "%s: unknown host\n", hostname );
572 if (( privfd = rresvport( &port )) < 0 ) {
573 syslog( LOG_ERR, "lp_connect: socket: %m" );
578 bzero( &sin, sizeof( struct sockaddr_in ));
579 sin.sin_family = AF_INET;
580 /* sin.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); */
581 bcopy( hp->h_addr, &sin.sin_addr, hp->h_length );
582 sin.sin_port = sp->s_port;
584 if ( connect( privfd, (struct sockaddr *)&sin,
585 sizeof( struct sockaddr_in )) < 0 ) {
586 syslog( LOG_ERR, "lp_connect: %m" );
600 if (( s = lp_conn_inet()) < 0 ) {
601 syslog( LOG_ERR, "lp_rmjob: %m" );
605 if ( lp.lp_person == NULL ) {
609 sprintf( buf, "\5%s %s %d\n", printer->p_printer, lp.lp_person, job );
611 if ( write( s, buf, n ) != n ) {
612 syslog( LOG_ERR, "lp_rmjob write: %m" );
613 lp_disconn_inet( s );
616 while (( n = read( s, buf, sizeof( buf ))) > 0 ) {
617 syslog( LOG_DEBUG, "read %.*s", n, buf );
620 lp_disconn_inet( s );
624 char *kw_rank = "Rank";
625 char *kw_active = "active";
627 char *tag_rank = "rank: ";
628 char *tag_owner = "owner: ";
629 char *tag_job = "job: ";
630 char *tag_files = "files: ";
631 char *tag_size = "size: ";
632 char *tag_status = "status: ";
637 char buf[ 1024 ], *start, *stop, *p, *q;
638 int linelength, crlflength;
639 static struct papfile pf;
642 if (( s = lp_conn_unix()) < 0 ) {
643 syslog( LOG_ERR, "lp_queue: %m" );
647 sprintf( buf, "\3%s\n", printer->p_printer );
649 if ( write( s, buf, n ) != n ) {
650 syslog( LOG_ERR, "lp_queue write: %m" );
651 lp_disconn_unix( s );
654 pf.pf_state = PF_BOT;
656 while (( n = read( s, buf, sizeof( buf ))) > 0 ) {
657 append( &pf, buf, n );
661 if ( markline( &pf, &start, &linelength, &crlflength ) > 0 ) {
663 stop = start + linelength;
664 for ( p = start; p < stop; p++ ) {
665 if ( *p == ' ' || *p == '\t' ) {
670 CONSUME( &pf , linelength + crlflength);
675 * Keys: "Rank", a number, "active"
676 * Anything else is status.
679 if ( len == strlen( kw_rank ) &&
680 strncmp( kw_rank, start, len ) == 0 ) {
681 CONSUME( &pf, linelength + crlflength );
684 if (( len == strlen( kw_active ) &&
685 strncmp( kw_active, start, len ) == 0 ) ||
686 isdigit( *start )) { /* a job line */
687 append( out, tag_rank, strlen( tag_rank ));
688 append( out, start, p - start );
689 append( out, "\n", 1 );
691 for ( ; p < stop; p++ ) {
692 if ( *p != ' ' && *p != '\t' ) {
696 for ( q = p; p < stop; p++ ) {
697 if ( *p == ' ' || *p == '\t' ) {
702 append( out, ".\n", 2 );
703 CONSUME( &pf, linelength + crlflength );
706 append( out, tag_owner, strlen( tag_owner ));
707 append( out, q, p - q );
708 append( out, "\n", 1 );
710 for ( ; p < stop; p++ ) {
711 if ( *p != ' ' && *p != '\t' ) {
715 for ( q = p; p < stop; p++ ) {
716 if ( *p == ' ' || *p == '\t' ) {
721 append( out, ".\n", 2 );
722 CONSUME( &pf , linelength + crlflength );
725 append( out, tag_job, strlen( tag_job ));
726 append( out, q, p - q );
727 append( out, "\n", 1 );
729 for ( ; p < stop; p++ ) {
730 if ( *p != ' ' && *p != '\t' ) {
734 for ( q = p, p = stop; p > q; p-- ) {
735 if ( *p == ' ' || *p == '\t' ) {
739 for ( ; p > q; p-- ) {
740 if ( *p != ' ' && *p != '\t' ) {
744 for ( ; p > q; p-- ) {
745 if ( *p == ' ' || *p == '\t' ) {
750 append( out, ".\n", 2 );
751 CONSUME( &pf, linelength + crlflength );
754 append( out, tag_files, strlen( tag_files ));
755 append( out, q, p - q );
756 append( out, "\n", 1 );
758 for ( ; p < stop; p++ ) {
759 if ( *p != ' ' && *p != '\t' ) {
763 append( out, tag_size, strlen( tag_size ));
764 append( out, p, stop - p );
765 append( out, "\n.\n", 3 );
767 CONSUME( &pf, linelength + crlflength );
772 append( out, tag_status, strlen( tag_status ));
773 append( out, start, linelength );
774 append( out, "\n.\n", 3 );
776 CONSUME( &pf, linelength + crlflength );
778 append( out, "*\n", 2 );
779 lp_disconn_unix( s );