xref: /freebsd/usr.sbin/lpr/lpd/recvjob.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by the University of
17  *	California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifndef lint
36 static const char copyright[] =
37 "@(#) Copyright (c) 1983, 1993\n\
38 	The Regents of the University of California.  All rights reserved.\n";
39 #endif /* not lint */
40 
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)recvjob.c	8.2 (Berkeley) 4/27/95";
44 #endif
45 static const char rcsid[] =
46 	"$Id: recvjob.c,v 1.12 1997/12/02 20:45:59 wollman Exp $";
47 #endif /* not lint */
48 
49 /*
50  * Receive printer jobs from the network, queue them and
51  * start the printer daemon.
52  */
53 #include <sys/param.h>
54 #include <sys/mount.h>
55 #include <sys/stat.h>
56 
57 #include <unistd.h>
58 #include <signal.h>
59 #include <fcntl.h>
60 #include <dirent.h>
61 #include <syslog.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include "lp.h"
66 #include "lp.local.h"
67 #include "extern.h"
68 #include "pathnames.h"
69 
70 #define ack()	(void) write(1, sp, 1);
71 
72 static char	 dfname[NAME_MAX];	/* data files */
73 static int	 minfree;       /* keep at least minfree blocks available */
74 static char	*sp = "";
75 static char	 tfname[NAME_MAX];	/* tmp copy of cf before linking */
76 
77 static int        chksize __P((int));
78 static void       frecverr __P((const char *, ...));
79 static int        noresponse __P((void));
80 static void       rcleanup __P((int));
81 static int        read_number __P((char *));
82 static int        readfile __P((char *, int));
83 static int        readjob __P((struct printer *pp));
84 
85 
86 void
87 recvjob(printer)
88 	const char *printer;
89 {
90 	struct stat stb;
91 	int status;
92 	struct printer myprinter, *pp = &myprinter;
93 
94 	/*
95 	 * Perform lookup for printer name or abbreviation
96 	 */
97 	init_printer(pp);
98 	status = getprintcap(printer, pp);
99 	switch (status) {
100 	case PCAPERR_OSERR:
101 		frecverr("cannot open printer description file");
102 		break;
103 	case PCAPERR_NOTFOUND:
104 		frecverr("unknown printer %s", printer);
105 		break;
106 	case PCAPERR_TCLOOP:
107 		fatal(pp, "potential reference loop detected in printcap file");
108 	default:
109 		break;
110 	}
111 
112 	(void) close(2);			/* set up log file */
113 	if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) {
114 		syslog(LOG_ERR, "%s: %m", pp->log_file);
115 		(void) open(_PATH_DEVNULL, O_WRONLY);
116 	}
117 
118 	if (chdir(pp->spool_dir) < 0)
119 		frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
120 	if (stat(pp->lock_file, &stb) == 0) {
121 		if (stb.st_mode & 010) {
122 			/* queue is disabled */
123 			putchar('\1');		/* return error code */
124 			exit(1);
125 		}
126 	} else if (stat(pp->spool_dir, &stb) < 0)
127 		frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
128 	minfree = 2 * read_number("minfree");	/* scale KB to 512 blocks */
129 	signal(SIGTERM, rcleanup);
130 	signal(SIGPIPE, rcleanup);
131 
132 	if (readjob(pp))
133 		printjob(pp);
134 }
135 
136 /*
137  * Read printer jobs sent by lpd and copy them to the spooling directory.
138  * Return the number of jobs successfully transfered.
139  */
140 static int
141 readjob(pp)
142 	struct printer *pp;
143 {
144 	register int size, nfiles;
145 	register char *cp;
146 
147 	ack();
148 	nfiles = 0;
149 	for (;;) {
150 		/*
151 		 * Read a command to tell us what to do
152 		 */
153 		cp = line;
154 		do {
155 			if ((size = read(1, cp, 1)) != 1) {
156 				if (size < 0)
157 					frecverr("%s: lost connection",
158 					    pp->printer);
159 				return(nfiles);
160 			}
161 		} while (*cp++ != '\n' && (cp - line + 1) < sizeof(line));
162 		if (cp - line + 1 >= sizeof(line))
163 			frecverr("readjob overflow");
164 		*--cp = '\0';
165 		cp = line;
166 		switch (*cp++) {
167 		case '\1':	/* cleanup because data sent was bad */
168 			rcleanup(0);
169 			continue;
170 
171 		case '\2':	/* read cf file */
172 			size = 0;
173 			while (*cp >= '0' && *cp <= '9')
174 				size = size * 10 + (*cp++ - '0');
175 			if (*cp++ != ' ')
176 				break;
177 			/*
178 			 * host name has been authenticated, we use our
179 			 * view of the host name since we may be passed
180 			 * something different than what gethostbyaddr()
181 			 * returns
182 			 */
183 			strncpy(cp + 6, from, sizeof(line) + line - cp - 7);
184 			line[sizeof(line) - 1 ] = '\0';
185 			strncpy(tfname, cp, sizeof(tfname) - 1);
186 			tfname[sizeof (tfname) - 1] = '\0';
187 			tfname[0] = 't';
188 			if (strchr(tfname, '/'))
189 				frecverr("readjob: %s: illegal path name",
190 				    tfname);
191 			if (!chksize(size)) {
192 				(void) write(1, "\2", 1);
193 				continue;
194 			}
195 			if (!readfile(tfname, size)) {
196 				rcleanup(0);
197 				continue;
198 			}
199 			if (link(tfname, cp) < 0)
200 				frecverr("%s: %m", tfname);
201 			(void) unlink(tfname);
202 			tfname[0] = '\0';
203 			nfiles++;
204 			continue;
205 
206 		case '\3':	/* read df file */
207 			size = 0;
208 			while (*cp >= '0' && *cp <= '9')
209 				size = size * 10 + (*cp++ - '0');
210 			if (*cp++ != ' ')
211 				break;
212 			if (!chksize(size)) {
213 				(void) write(1, "\2", 1);
214 				continue;
215 			}
216 			(void) strncpy(dfname, cp, sizeof(dfname) - 1);
217 			dfname[sizeof(dfname) - 1] = '\0';
218 			if (strchr(dfname, '/'))
219 				frecverr("readjob: %s: illegal path name",
220 					dfname);
221 			(void) readfile(dfname, size);
222 			continue;
223 		}
224 		frecverr("protocol screwup: %s", line);
225 	}
226 }
227 
228 /*
229  * Read files send by lpd and copy them to the spooling directory.
230  */
231 static int
232 readfile(file, size)
233 	char *file;
234 	int size;
235 {
236 	register char *cp;
237 	char buf[BUFSIZ];
238 	register int i, j, amt;
239 	int fd, err;
240 
241 	fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD);
242 	if (fd < 0)
243 		frecverr("readfile: %s: illegal path name: %m", file);
244 	ack();
245 	err = 0;
246 	for (i = 0; i < size; i += BUFSIZ) {
247 		amt = BUFSIZ;
248 		cp = buf;
249 		if (i + amt > size)
250 			amt = size - i;
251 		do {
252 			j = read(1, cp, amt);
253 			if (j <= 0)
254 				frecverr("lost connection");
255 			amt -= j;
256 			cp += j;
257 		} while (amt > 0);
258 		amt = BUFSIZ;
259 		if (i + amt > size)
260 			amt = size - i;
261 		if (write(fd, buf, amt) != amt) {
262 			err++;
263 			break;
264 		}
265 	}
266 	(void) close(fd);
267 	if (err)
268 		frecverr("%s: write error", file);
269 	if (noresponse()) {		/* file sent had bad data in it */
270 		if (strchr(file, '/') == NULL)
271 			(void) unlink(file);
272 		return(0);
273 	}
274 	ack();
275 	return(1);
276 }
277 
278 static int
279 noresponse()
280 {
281 	char resp;
282 
283 	if (read(1, &resp, 1) != 1)
284 		frecverr("lost connection");
285 	if (resp == '\0')
286 		return(0);
287 	return(1);
288 }
289 
290 /*
291  * Check to see if there is enough space on the disk for size bytes.
292  * 1 == OK, 0 == Not OK.
293  */
294 static int
295 chksize(size)
296 	int size;
297 {
298 	int spacefree;
299 	struct statfs sfb;
300 
301 	if (statfs(".", &sfb) < 0) {
302 		syslog(LOG_ERR, "%s: %m", "statfs(\".\")");
303 		return (1);
304 	}
305 	spacefree = sfb.f_bavail * (sfb.f_bsize / 512);
306 	size = (size + 511) / 512;
307 	if (minfree + size > spacefree)
308 		return(0);
309 	return(1);
310 }
311 
312 static int
313 read_number(fn)
314 	char *fn;
315 {
316 	char lin[80];
317 	register FILE *fp;
318 
319 	if ((fp = fopen(fn, "r")) == NULL)
320 		return (0);
321 	if (fgets(lin, 80, fp) == NULL) {
322 		fclose(fp);
323 		return (0);
324 	}
325 	fclose(fp);
326 	return (atoi(lin));
327 }
328 
329 /*
330  * Remove all the files associated with the current job being transfered.
331  */
332 static void
333 rcleanup(signo)
334 	int signo;
335 {
336 	if (tfname[0] && strchr(tfname, '/') == NULL)
337 		(void) unlink(tfname);
338 	if (dfname[0] && strchr(dfname, '/') == NULL) {
339 		do {
340 			do
341 				(void) unlink(dfname);
342 			while (dfname[2]-- != 'A');
343 			dfname[2] = 'z';
344 		} while (dfname[0]-- != 'd');
345 	}
346 	dfname[0] = '\0';
347 }
348 
349 #ifdef __STDC__
350 #include <stdarg.h>
351 #else
352 #include <varargs.h>
353 #endif
354 
355 static void
356 #ifdef __STDC__
357 frecverr(const char *msg, ...)
358 #else
359 frecverr(msg, va_alist)
360 	char *msg;
361         va_dcl
362 #endif
363 {
364 	va_list ap;
365 #ifdef __STDC__
366 	va_start(ap, msg);
367 #else
368 	va_start(ap);
369 #endif
370 	rcleanup(0);
371 	syslog(LOG_ERR, "%s", fromb);
372 	vsyslog(LOG_ERR, msg, ap);
373 	va_end(ap);
374 	putchar('\1');		/* return error code */
375 	exit(1);
376 }
377