1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  */
27 
28 /* $Id: in.lpd.c 170 2006-05-20 05:58:49Z njacobs $ */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <syslog.h>
38 #include <libintl.h>
39 
40 #include <papi.h>
41 #include "common.h"
42 
43 #define	ACK(fp)		{ (void) fputc('\0', fp); (void) fflush(fp); }
44 #define	NACK(fp)	{ (void) fputc('\1', fp); (void) fflush(fp); }
45 
46 /*
47  * This file contains the front-end of the BSD Print Protocol adaptor.  This
48  * code assumes a BSD Socket interface to the networking side.
49  */
50 
51 void
52 fatal(FILE *fp, char *fmt, ...)
53 {
54 	va_list ap;
55 
56 	va_start(ap, fmt);
57 	vsyslog(LOG_DEBUG, fmt, ap);
58 	vfprintf(fp, fmt, ap);
59 	va_end(ap);
60 }
61 
62 static void
63 cleanup(char **files)
64 {
65 	if (files != NULL) {
66 		int i;
67 
68 		for (i = 0; files[i] != NULL; i++)
69 			unlink(files[i]);
70 	}
71 }
72 
73 static void
74 berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp)
75 {
76 	char line[BUFSIZ];
77 	char **files = NULL;	/* the job data files */
78 
79 	/* This should actually implement transfer job from RFC-1179 */
80 	ACK(ofp);
81 
82 	while (fgets(line, sizeof (line), ifp) != NULL) {
83 		switch (line[0]) {
84 		case 0x01:	/* Abort */
85 			cleanup(files);
86 			break;
87 		case 0x02:	/* Receive control file */
88 
89 			break;
90 		case 0x03: {	/* Receive data file */
91 			char file[] = "lpdXXXXXX";
92 			int fd;
93 
94 			fd = mkstemp(file);
95 
96 			list_append(&files, strdup(file));
97 			}
98 			break;
99 		default:
100 			fatal(ofp, "protocol screwup");
101 			cleanup(files);
102 			break;
103 		}
104 	}
105 
106 	cleanup(files);
107 }
108 
109 static void
110 berkeley_transfer_files(papi_service_t svc, FILE *ifp, FILE *ofp,
111 		char *printer)
112 {
113 	papi_status_t status;
114 	papi_printer_t p = NULL;
115 	char *keys[] = { "printer-is-accepting", NULL };
116 
117 	status = papiPrinterQuery(svc, printer, keys, NULL, &p);
118 	if ((status == PAPI_OK) && (p != NULL)) {
119 		papi_attribute_t **attrs = papiPrinterGetAttributeList(p);
120 		char accepting = PAPI_FALSE;
121 
122 		papiAttributeListGetBoolean(attrs, NULL,
123 				"printer-is-accepting", &accepting);
124 
125 		if (accepting == PAPI_TRUE)
126 			berkeley_receive_files(svc, ifp, ofp);
127 		else
128 			NACK(ofp);
129 
130 		papiPrinterFree(p);
131 	} else
132 		NACK(ofp);
133 }
134 
135 /*
136  * This is the entry point for this program.  The program takes the
137  * following options:
138  * 	(none)
139  */
140 int
141 main(int ac, char *av[])
142 {
143 	papi_status_t status;
144 	papi_service_t svc = NULL;
145 	papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
146 	FILE	*ifp = stdin,
147 		*ofp = stdout;
148 	int	c;
149 	char	buf[BUFSIZ],
150 		**args,
151 		*printer;
152 
153 	openlog("bsd-gw", LOG_PID, LOG_LPR);
154 
155 	while ((c = getopt(ac, av, "d")) != EOF)
156 		switch (c) {
157 		case 'E':
158 			encryption = PAPI_ENCRYPT_ALWAYS;
159 			break;
160 		case 'd':
161 		default:
162 			;
163 		}
164 
165 	if (fgets(buf, sizeof (buf), ifp) == NULL) {
166 		if (feof(ifp) == 0)
167 			syslog(LOG_ERR, "Error reading from connection: %s",
168 				strerror(errno));
169 		exit(1);
170 	}
171 
172 	if ((buf[0] < 1) || (buf[0] > 5)) {
173 		fatal(ofp, "Invalid protocol request (%d): %c%s\n",
174 			buf[0], buf[0], buf);
175 		exit(1);
176 	}
177 
178 	args = strsplit(&buf[1], "\t\n ");
179 	printer = *args++;
180 
181 	if (printer == NULL) {
182 		fatal(ofp, "Can't determine requested printer");
183 		exit(1);
184 	}
185 
186 	status = papiServiceCreate(&svc, printer, NULL, NULL, NULL,
187 					encryption, NULL);
188 	if (status != PAPI_OK) {
189 		fatal(ofp, "Failed to contact service for %s: %s\n", printer,
190 			verbose_papi_message(svc, status));
191 		exit(1);
192 	}
193 
194 #ifdef HAVE_IS_SYSTEM_LABELED
195 	if (is_system_labeled()) {
196 		int fd = fileno(ifp);
197 
198 		(void) papiServiceSetPeer(svc, fd);
199 	}
200 #endif
201 
202 	switch (buf[0]) {
203 	case '\1':	/* restart printer */
204 		ACK(ofp);	/* there is no equivalent */
205 		break;
206 	case '\2':	/* transfer job(s) */
207 		berkeley_transfer_files(svc, ifp, ofp, printer);
208 		break;
209 	case '\3':	/* show queue (short) */
210 	case '\4': {	/* show queue (long) */
211 		int count;
212 
213 		for (count = 0; args[count] != 0; count++);
214 
215 		berkeley_queue_report(svc, ofp, printer, buf[0], count, args);
216 		}
217 		break;
218 	case '\5': {	/* cancel job(s) */
219 		char *requestor = *args++;
220 		int count;
221 
222 		status = papiServiceSetUserName(svc, requestor);
223 		for (count = 0; args[count] != 0; count++);
224 
225 		berkeley_cancel_request(svc, ofp, printer, count, args);
226 		}
227 		break;
228 	default:
229 		fatal(ofp, "unsupported protocol request (%c), %s",
230 			buf[0], &buf[1]);
231 	}
232 
233 	(void) fflush(ofp);
234 
235 	syslog(LOG_DEBUG, "protocol request(%d) for %s completed: %s",
236 		buf[0], printer, papiStatusString(status));
237 	syslog(LOG_DEBUG, "detail: %s", verbose_papi_message(svc, status));
238 
239 	papiServiceDestroy(svc);
240 
241 	return (0);
242 }
243