xref: /illumos-gate/usr/src/cmd/lp/model/netpr/netpr.c (revision 355b4669e025ff377602b6fc7caaf30dbc218371)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <libintl.h>
32 #include <locale.h>
33 #include <signal.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/mman.h>
38 #include <sys/socket.h>
39 #include <fcntl.h>
40 #include <syslog.h>
41 #include "netpr.h"
42 
43 static void usage_exit();
44 
45 static void pipehandler(int);
46 char data_file_type = 0;
47 
48 int
49 main(int argc, char *argv[])
50 {
51 	extern char *optarg;
52 	extern int optind;
53 	int opt;
54 	np_job_t *job_data;
55 	char *destination = NULL;
56 	np_bsdjob_t *bsdjob;
57 	np_tcpjob_t *tcpjob;
58 	int sockfd;
59 	int pr_order = CONTROL_FIRST;
60 	char *vendor_pr_name = NULL;
61 	char *tcp_port = NULL;
62 	size_t filesize;
63 	int fd;
64 	caddr_t pa;
65 	int jobstatus;
66 	int exit_status = 0;
67 	int on = 1;
68 
69 
70 	(void) setlocale(LC_ALL, "");
71 #if	!defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
72 #define	TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
73 #endif
74 	(void) textdomain(TEXT_DOMAIN);
75 
76 	openlog("netpr", LOG_PID, LOG_LPR);
77 	(void) signal(SIGPIPE, pipehandler);
78 
79 	/* reduce privileges until needed to open reserved port */
80 	if (seteuid(getuid())) {
81 		syslog(LOG_DEBUG, "seteuid failed, exiting netpr");
82 		exit(E_FAILURE);
83 	}
84 
85 	if ((job_data = init_job()) == NULL) {
86 		fprintf(stderr, gettext("init_job(): out of memory\n"));
87 		exit(E_RETRY);
88 	}
89 
90 	while ((opt = getopt(argc, argv, "f:I:p:d:T:P:t:U:c:b")) != EOF)
91 		switch (opt) {
92 		case 'f':
93 			data_file_type = optarg[0];
94 			break;
95 		case 'I': /* foo-49 */
96 			job_data->request_id = alloc_str((char *)optarg);
97 			syslog(LOG_DEBUG, "request_id: %s",
98 				job_data->request_id);
99 			break;
100 		case 'U': /* awe172-126!wendyp */
101 			job_data->username = alloc_str((char *)optarg);
102 			syslog(LOG_DEBUG, "username: %s",
103 				job_data->username);
104 			break;
105 		case 'p': /* foo */
106 			job_data->printer = alloc_str((char *)optarg);
107 			syslog(LOG_DEBUG, "printer: %s",
108 				job_data->printer);
109 			break;
110 		case 'd': /* server for printer */
111 			job_data->dest = alloc_str((char *)optarg);
112 			syslog(LOG_DEBUG, "dest: %s",
113 				job_data->dest);
114 			break;
115 		case 'T': /* /tmp/file2 */
116 			job_data->title = alloc_str((char *)optarg);
117 			syslog(LOG_DEBUG, "title: %s",
118 				job_data->title);
119 			break;
120 		case 'P':
121 			if ((strcmp(optarg, "bsd")) == 0)
122 				job_data->protocol = BSD;
123 			else if ((strcmp(optarg, "tcp")) == 0)
124 				job_data->protocol = TCP;
125 			else
126 				usage_exit();
127 
128 			syslog(LOG_DEBUG, "protocol: %d",
129 				job_data->protocol);
130 			break;
131 		case 't':
132 			job_data->timeout = atoi(optarg);
133 			if (job_data->timeout < 0)
134 				usage_exit();
135 			break;
136 		case 'c':
137 			if ((strcmp(optarg, "first")) == 0)
138 				pr_order = CONTROL_FIRST;
139 			else if ((strcmp(optarg, "last")) == 0)
140 				pr_order = DATA_FIRST;
141 			else
142 				usage_exit();
143 
144 			syslog(LOG_DEBUG, "bsd print order: %d", pr_order);
145 			break;
146 		case 'b':
147 			job_data->banner = NOBANNER;
148 			syslog(LOG_DEBUG, "banner : %d",
149 				job_data->banner);
150 			break;
151 		case '?':
152 			usage_exit();
153 		}
154 
155 
156 	if ((job_data->dest == NULL) || (job_data->request_id == NULL) ||
157 		(job_data->printer == NULL) || (job_data->username == NULL))
158 		usage_exit();
159 
160 	/*
161 	 * Check that there is a file
162 	 */
163 	if (optind == argc) {
164 		usage_exit();
165 	}
166 
167 	job_data->filename = alloc_str(argv[optind]);
168 	syslog(LOG_DEBUG, "filename : %s", job_data->filename);
169 
170 
171 	/*
172 	 * Sanity check the file
173 	 * returns filesize
174 	 */
175 
176 	if ((filesize = check_file(job_data->filename)) == -1) {
177 		syslog(LOG_DEBUG, "Skipping file %s",
178 		job_data->filename ? job_data->filename : "Error NULL file");
179 
180 		switch (errno) {
181 		case EISDIR:
182 			(void) fprintf(stderr,
183 			gettext("Netpr: %s: Not a regular file\n"),
184 			(job_data->filename ? job_data->filename : "Noname"));
185 			syslog(LOG_DEBUG, "Not a regular file");
186 			break;
187 		case ESRCH:
188 			(void) fprintf(stderr,
189 			gettext("Netpr: %s: Empty file\n"),
190 			(job_data->filename ? job_data->filename : "Noname"));
191 			syslog(LOG_DEBUG, "Empty file");
192 			break;
193 		default:
194 			perror(job_data->filename);
195 			(void) fprintf(stderr,
196 			gettext("Netpr: Cannot access file %s\n"),
197 			(job_data->filename ? job_data->filename : "Noname"));
198 			syslog(LOG_DEBUG, "Cannot access file.");
199 			break;
200 
201 		}
202 
203 		/*
204 		 * This file not valid, so bail
205 		 * Exit with zero so system will keep printing
206 		 */
207 		exit(0);
208 	}
209 
210 	/*
211 	 * file looks ok, open and mmap it
212 	 */
213 	if ((fd = open(job_data->filename, O_RDONLY)) < 0) {
214 		(void) fprintf(stderr, gettext("Netpr: Cannot open file %s\n"),
215 		(job_data->filename ? job_data->filename : "Error: NULL file"));
216 		syslog(LOG_DEBUG, "Cannot open file: %s",
217 		job_data->filename ? job_data->filename : "Error NULL file");
218 		exit(E_BAD_FILE);
219 	}
220 
221 	if ((pa = mmap((caddr_t)0, filesize, PROT_READ,
222 		(MAP_SHARED | MAP_NORESERVE), fd, (off_t)0)) == MAP_FAILED) {
223 
224 		(void) close(fd);
225 		(void) fprintf(stderr, gettext("Netpr: Cannot mmap file %s"),
226 		(job_data->filename ? job_data->filename : "Error: NULL file"));
227 
228 		syslog(LOG_DEBUG, "Cannot mmap file: %s",
229 		job_data->filename ? job_data->filename : "Error NULL file");
230 
231 		exit(E_RETRY);
232 	}
233 
234 
235 	if (job_data->protocol == BSD) {
236 		bsdjob = (np_bsdjob_t *)
237 			create_bsd_job(job_data, pr_order, filesize);
238 		if (bsdjob == NULL)
239 			exit(E_FAILURE);
240 	} else {
241 		tcpjob = (np_tcpjob_t *)create_tcp_job(job_data, filesize);
242 		if (tcpjob == NULL)
243 			exit(E_FAILURE);
244 	}
245 
246 	/*
247 	 * Parse destination
248 	 */
249 
250 	if ((strpbrk(job_data->dest, DEST_SEP)) != NULL) {
251 		if (job_data->protocol == BSD) {
252 			parse_dest(job_data->dest, &destination,
253 				&vendor_pr_name, DEST_SEP);
254 			if (vendor_pr_name != NULL) {
255 				bsdjob->np_printer = vendor_pr_name;
256 				syslog(LOG_DEBUG, "bsd vendor name: %s",
257 					bsdjob->np_printer);
258 			}
259 		} else {
260 			parse_dest(job_data->dest, &destination, &tcp_port,
261 				DEST_SEP);
262 			if (tcp_port != NULL)
263 				tcpjob->np_port = tcp_port;
264 				syslog(LOG_DEBUG, "tcp_port %s",
265 					tcpjob->np_port);
266 		}
267 		if (destination == NULL ||
268 			(job_data->protocol == TCP && tcp_port == NULL)) {
269 		    (void) fprintf(stderr,
270 		    gettext("Netpr: system error parsing destination %s\n"),
271 		    job_data->dest);
272 		    syslog(LOG_DEBUG, "system error parsing destination %s",
273 			job_data->dest);
274 
275 		    exit(E_FAILURE);
276 		}
277 
278 	} else {
279 		destination = job_data->dest;
280 	}
281 	syslog(LOG_DEBUG, "destination : %s", destination);
282 
283 	/*
284 	 * We are now ready to open a connection to the printer
285 	 * and print each of the files
286 	 */
287 
288 	if (job_data->protocol == BSD) {
289 
290 		/* set privileges to get reserved port */
291 		if (seteuid(0)) {
292 			syslog(LOG_DEBUG, "seteuid(0) failed, exiting netpr");
293 			exit(E_FAILURE);
294 		}
295 		if ((sockfd =  net_open(destination, 20)) < 0) {
296 			(void) fprintf(stderr,
297 			    gettext("Netpr: Cannot open connection to <%s>\n"),
298 			    destination);
299 			    syslog(LOG_DEBUG,
300 				"Cannot open connection to %s: retrying",
301 				destination);
302 			exit(E_RETRY);
303 		}
304 	} else {
305 		if ((sockfd = tcp_open(destination, tcpjob, 20)) == -1) {
306 			exit(E_RETRY);
307 		}
308 	}
309 
310 	/* lower privileges as we now have the reserved port */
311 	if (setuid(getuid())) {
312 		syslog(LOG_DEBUG, "setuid() failed, exiting netpr");
313 		exit(E_FAILURE);
314 	}
315 
316 
317 	/* Set SO_KEEPALIVE on socket to keep open */
318 	if ((setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
319 			(char *)&on, sizeof (on))) < 0) {
320 		syslog(LOG_DEBUG, "setsocket (SO_KEEPALIVE): %m");
321 	}
322 
323 	if (job_data->protocol == BSD) {
324 		if ((jobstatus = bsd_print(sockfd, pa,  bsdjob)) != 0) {
325 			(void) fprintf(stderr,
326 			gettext("Netpr: Error return from bsd_print <%d>\n"),
327 			jobstatus);
328 			syslog(LOG_DEBUG,
329 				"Error return from bsd_print <%d>", jobstatus);
330 			exit_status = E_RETRY;
331 		}
332 	} else {
333 		if ((jobstatus =
334 			tcp_print(sockfd, pa, tcpjob)) != 0) {
335 			(void) fprintf(stderr,
336 			gettext("Netpr: Error return from tcp_print <%d>\n"),
337 			jobstatus);
338 			syslog(LOG_DEBUG,
339 				"Error return from tcp_print <%d>", jobstatus);
340 			exit_status = E_RETRY;
341 		}
342 	}
343 
344 	(void) close(fd);
345 	(void) close(sockfd);
346 	(void) munmap(pa, filesize);
347 
348 	syslog(LOG_DEBUG, "exit status: %d", exit_status);
349 	return (exit_status);
350 }
351 
352 static void
353 usage_exit()
354 {
355 	(void) fprintf(stderr,
356 	gettext("Usage: netpr -I request_id -p printer -d destination\n"));
357 	(void) fprintf(stderr,
358 	gettext("\t\t-U username [ -f type ] [ -T title ] [ -P protocol ]\n"));
359 	(void) fprintf(stderr,
360 	    gettext("\t\t[-t timeout] [ -c ] [ -b ]\n"));
361 	(void) fprintf(stderr, gettext("\t\tfiles\n"));
362 	exit(E_BAD_INPUT);
363 }
364 
365 /*ARGSUSED*/
366 void
367 pipehandler(int i)
368 {
369 	(void) signal(SIGPIPE, pipehandler);
370 	syslog(LOG_DEBUG, "Received SIGPIPE, connection to printer broken");
371 	exit(E_SIGPIPE);
372 }
373