GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/lpr/lpd/recvjob.c Lines: 0 149 0.0 %
Date: 2017-11-07 Branches: 0 112 0.0 %

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