xref: /openbsd/usr.sbin/lpd/lp.c (revision 3a50f0a9)
1 /*	$OpenBSD: lp.c,v 1.4 2022/12/28 21:30:17 jmc Exp $	*/
2 
3 /*
4  * Copyright (c) 2017 Eric Faurot <eric@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "lp.h"
35 
36 #include "log.h"
37 
38 #define XXX_PID_MAX 99999
39 
40 struct qentry {
41 	char *name;
42 	time_t mtime;
43 };
44 
45 static int readent(struct lp_printer *, char *);
46 static int qentrycmp(const void *, const void *);
47 static int fullpath(struct lp_printer *, const char *, char *, size_t);
48 static int checksize(struct lp_printer *, size_t);
49 
50 static int scanning;
51 static char *db[] = {
52 	_PATH_PRINTCAP,
53 	NULL,
54 };
55 
56 /*
57  * Fill a printer structure from its /etc/printcap entry.
58  * Return 0 on success, or -1 on error.
59  */
60 int
lp_getprinter(struct lp_printer * lp,const char * name)61 lp_getprinter(struct lp_printer *lp, const char *name)
62 {
63 	char *buf = NULL;
64 	int r;
65 
66 	memset(lp, 0, sizeof(*lp));
67 
68 	r = cgetent(&buf, db, name);
69 	if (r == 0)
70 		r = readent(lp, buf);
71 	free(buf);
72 
73 	switch (r) {
74 	case -3:
75 		log_warnx("%s: potential reference loop", name);
76 		break;
77 	case -2:
78 		log_warn("%s", name);
79 		break;
80 	case -1:
81 		log_warnx("%s: unknown printer", name);
82 		break;
83 	case 0:
84 		return 0;
85 	case 1:
86 		log_warnx("%s: unresolved tc expansion", name);
87 		break;
88 	default:
89 		log_warnx("%s: unexpected return value %d", name, r);
90 	}
91 
92 	lp_clearprinter(lp);
93 	return -1;
94 }
95 
96 /*
97  * Iterate over /etc/printcap and fill the printer structure from the next
98  * entry, if any.
99  *
100  * Return 0 if no entry is found.
101  *        1 if a printer is filled.
102  *       -1 on error, and set errno.
103  */
104 int
lp_scanprinters(struct lp_printer * lp)105 lp_scanprinters(struct lp_printer *lp)
106 {
107 	char *buf;
108 	int r, saved_errno;
109 
110 	if (scanning++ == 0)
111 		r = cgetfirst(&buf, db);
112 	else
113 		r = cgetnext(&buf, db);
114 
115 	if (r == 0) {
116 		cgetclose();
117 		scanning = 0;
118 		return 0;
119 	} else if (r == 1) {
120 		memset(lp, 0, sizeof(*lp));
121 		r = readent(lp, buf);
122 		free(buf);
123 		if (r == -2)
124 			goto fail;
125 		return 1;
126 	} else if (r == -1)
127 		fatal("cannot open %s", _PATH_PRINTCAP);
128 	else if (r == -2)
129 		errno = ELOOP; /* potential reference loop */
130 
131     fail:
132 	saved_errno = errno;
133 	lp_clearprinter(lp);
134 	cgetclose();
135 	scanning = 0;
136 	errno = saved_errno;
137 	return -1;
138 }
139 
140 static int
readent(struct lp_printer * lp,char * buf)141 readent(struct lp_printer *lp, char *buf)
142 {
143 	char *s;
144 
145 	s = strchr(buf, ':');
146 	if (s)
147 		*s = '\0';
148 	lp->lp_name = strdup(buf);
149 	if (s)
150 		*s = ':';
151 	if (lp->lp_name == NULL)
152 		return -2;
153 
154 	s = lp->lp_name;
155 	while ((s = strchr(s, '|'))) {
156 		*s++ = '\0';
157 		if (lp->lp_aliascount < LP_MAXALIASES)
158 			lp->lp_aliases[lp->lp_aliascount++] = s;
159 	}
160 
161 #define CGETSTR(x)	if (cgetstr(buf, #x, &(lp->lp_ ## x)) == -2) \
162 				goto fail
163 #define CGETNUM(x, d)	if (cgetnum(buf, #x, &(lp->lp_ ## x)) == -1) \
164 				(lp->lp_ ## x) = d;
165 #define CGETBOOL(x) lp->lp_ ## x = cgetcap(buf, #x, ':') ? 1 : 0
166 
167 	CGETSTR(af);
168 	CGETNUM(br, 0);
169 	CGETSTR(cf);
170 	CGETSTR(df);
171 	CGETSTR(ff);
172 	CGETBOOL(fo);
173 	CGETSTR(gf);
174 	CGETBOOL(hl);
175 	CGETBOOL(ic);
176 	CGETSTR(if);
177 	CGETSTR(lf);
178 	CGETSTR(lo);
179 	CGETSTR(lp);
180 	CGETNUM(mc, 0);
181 	CGETSTR(ms);
182 	CGETNUM(mx, 0);
183 	CGETSTR(nd);
184 	CGETSTR(nf);
185 	CGETSTR(of);
186 	CGETNUM(pc, DEFAULT_PC);
187 	CGETNUM(pl, DEFAULT_PL);
188 	CGETNUM(pw, DEFAULT_PW);
189 	CGETNUM(px, 0);
190 	CGETNUM(py, 0);
191 	CGETSTR(rf);
192 	CGETSTR(rg);
193 	CGETSTR(rm);
194 	CGETSTR(rp);
195 	CGETBOOL(rs);
196 	CGETBOOL(rw);
197 	CGETBOOL(sb);
198 	CGETBOOL(sc);
199 	CGETSTR(sd);
200 	CGETBOOL(sf);
201 	CGETBOOL(sh);
202 	CGETSTR(st);
203 	CGETSTR(tf);
204 	CGETSTR(tr);
205 	CGETSTR(vf);
206 
207 	if (lp->lp_rm && lp->lp_rm[0]) {
208 		lp->lp_type = PRN_LPR;
209 		lp->lp_host = lp->lp_rm;
210 		lp->lp_port = NULL;
211 	}
212 	else if (strchr(LP_LP(lp), '@')) {
213 		lp->lp_type = PRN_NET;
214 		lp->lp_port = strdup(LP_LP(lp));
215 		lp->lp_host = strchr(lp->lp_port, '@');
216 		*lp->lp_host++ = '\0';
217 	}
218 	else {
219 		lp->lp_type = PRN_LOCAL;
220 	}
221 
222 	return 0;
223     fail:
224 	return -2;
225 }
226 
227 void
lp_clearprinter(struct lp_printer * lp)228 lp_clearprinter(struct lp_printer *lp)
229 {
230 	free(lp->lp_name);
231 	free(lp->lp_port);
232 	if (lp->lp_lock)
233 		fclose(lp->lp_lock);
234 	free(lp->lp_af);
235 	free(lp->lp_cf);
236 	free(lp->lp_df);
237 	free(lp->lp_ff);
238 	free(lp->lp_gf);
239 	free(lp->lp_if);
240 	free(lp->lp_lf);
241 	free(lp->lp_lo);
242 	free(lp->lp_lp);
243 	free(lp->lp_ms);
244 	free(lp->lp_nd);
245 	free(lp->lp_nf);
246 	free(lp->lp_of);
247 	free(lp->lp_rf);
248 	free(lp->lp_rg);
249 	free(lp->lp_rm);
250 	free(lp->lp_rp);
251 	free(lp->lp_sd);
252 	free(lp->lp_st);
253 	free(lp->lp_tf);
254 	free(lp->lp_tr);
255 	free(lp->lp_vf);
256 	memset(lp, 0, sizeof(*lp));
257 }
258 
259 static int
qentrycmp(const void * aa,const void * bb)260 qentrycmp(const void *aa, const void *bb)
261 {
262 	const struct qentry *a = aa, *b = bb;
263 
264 	if (a->mtime < b->mtime)
265 		return -1;
266 	if (a->mtime > b->mtime)
267 		return 1;
268 
269 	return strcmp(a->name, b->name);
270 }
271 
272 /*
273  * Read the printer queue content.
274  * Return the task count, or -1 on error.
275  */
276 int
lp_readqueue(struct lp_printer * lp,struct lp_queue * q)277 lp_readqueue(struct lp_printer *lp, struct lp_queue *q)
278 {
279 	struct qentry *qe = NULL, *tqe;
280 	struct dirent *d;
281 	struct stat st;
282 	size_t len, sz, nqi, nqe = 0, nqa = 0, n, i;
283 	char path[PATH_MAX], *end;
284 	DIR *dp= NULL;
285 
286 	len = strlcpy(path, LP_SD(lp), sizeof(path));
287 	if (len == 0 || len >= sizeof(path)) {
288 		log_warn("%s: %s: invalid spool directory name",
289 		    __func__, LP_SD(lp));
290 		goto fail;
291 	}
292 
293 	if ((dp = opendir(path)) == NULL) {
294 		log_warn("%s: opendir", __func__);
295 		goto fail;
296 	}
297 
298 	if (fstat(dirfd(dp), &st) == -1) {
299 		log_warn("%s: fstat", __func__);
300 		goto fail;
301 	}
302 	/* Assume half the files are cf files. */
303 	nqi = st.st_nlink / 2;
304 
305 	if (path[len-1] != '/') {
306 		len = strlcat(path, "/", sizeof(path));
307 		if (len >= sizeof(path)) {
308 			errno = ENAMETOOLONG;
309 			log_warn("%s: strlcat", __func__);
310 			goto fail;
311 		}
312 	}
313 	end = path + len;
314 	sz = sizeof(path) - len;
315 
316 	errno = 0;
317 	while ((d = readdir(dp))) {
318 		if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
319 			continue;
320 
321 		if (strlen(d->d_name) < 7)
322 			continue;
323 
324 		if (!isdigit((unsigned char)d->d_name[3]) ||
325 		    !isdigit((unsigned char)d->d_name[4]) ||
326 		    !isdigit((unsigned char)d->d_name[5]))
327 			continue;
328 
329 		if (strlcpy(end, d->d_name, sz) >= sz) {
330 			errno = ENAMETOOLONG;
331 			log_warn("%s: strlcat", __func__);
332 			goto fail;
333 		}
334 
335 		if (stat(path, &st) == -1) {
336 			log_warn("%s: stat", __func__);
337 			goto fail;
338 		}
339 
340 		if (nqe == nqa) {
341 			n = nqa ? (nqa + 5) : nqi;
342 			tqe = recallocarray(qe, nqa, n, sizeof(*qe));
343 			if (tqe == NULL) {
344 				log_warn("%s: recallocarray", __func__);
345 				goto fail;
346 			}
347 			qe = tqe;
348 			nqa = n;
349 		}
350 
351 		if ((qe[nqe].name = strdup(d->d_name)) == NULL) {
352 			log_warn("%s: strdup", __func__);
353 			goto fail;
354 		}
355 		qe[nqe].mtime = st.st_mtime;
356 		nqe++;
357 	}
358 	if (errno) {
359 		log_warn("%s: readdir", __func__);
360 		goto fail;
361 	}
362 	closedir(dp);
363 	dp = NULL;
364 
365 	qsort(qe, nqe, sizeof(*qe), qentrycmp);
366 
367 	q->count = nqe;
368 	q->cfname = calloc(nqe, sizeof(*q->cfname));
369 	if (q->cfname == NULL) {
370 		log_warn("%s: calloc", __func__);
371 		goto fail;
372 	}
373 	for (i = 0; i < nqe; i++)
374 		q->cfname[i] = qe[i].name;
375 
376 	free(qe);
377 	return nqe;
378 
379     fail:
380 	if (dp)
381 		closedir(dp);
382 	for (i = 0; i < nqe; i++)
383 		free(qe[i].name);
384 	free(qe);
385 	lp_clearqueue(q);
386 	return -1;
387 }
388 
389 void
lp_clearqueue(struct lp_queue * q)390 lp_clearqueue(struct lp_queue *q)
391 {
392 	int i;
393 
394 	for (i = 0; i < q->count; i++)
395 		free(q->cfname[i]);
396 	free(q->cfname);
397 }
398 
399 static int
fullpath(struct lp_printer * lp,const char * fname,char * dst,size_t sz)400 fullpath(struct lp_printer *lp, const char *fname, char *dst, size_t sz)
401 {
402 	int r;
403 
404 	r = snprintf(dst, sz, "%s/%s", LP_SD(lp), fname);
405 	if (r < 0 || (size_t)r >= sz) {
406 		errno = ENAMETOOLONG;
407 		return -1;
408 	}
409 
410 	return 0;
411 }
412 
413 /*
414  * fopen(3) a file in the printer spooldir for reading.
415  */
416 FILE *
lp_fopen(struct lp_printer * lp,const char * fname)417 lp_fopen(struct lp_printer *lp, const char *fname)
418 {
419 	char path[PATH_MAX];
420 
421 	if (fullpath(lp, fname, path, sizeof(path)) == -1)
422 		return NULL;
423 
424 	return fopen(path, "r");
425 }
426 
427 /*
428  * unlink(2) a file in the printer spooldir.
429  */
430 int
lp_unlink(struct lp_printer * lp,const char * fname)431 lp_unlink(struct lp_printer *lp, const char *fname)
432 {
433 	char path[PATH_MAX];
434 
435 	if (fullpath(lp, fname, path, sizeof(path)) == -1)
436 		return -1;
437 
438 	return unlink(path);
439 }
440 
441 /*
442  * stat(2) a file in the printer spooldir.
443  */
444 int
lp_stat(struct lp_printer * lp,const char * fname,struct stat * st)445 lp_stat(struct lp_printer *lp, const char *fname, struct stat *st)
446 {
447 	char path[PATH_MAX];
448 
449 	if (fullpath(lp, fname, path, sizeof(path)) == -1)
450 		return -1;
451 
452 	return stat(path, st);
453 }
454 
455 /*
456  * Grab the lockfile for this printer, and associate it to the printer.
457  * Return -1 on error or 0 otherwise.
458  */
459 int
lp_lock(struct lp_printer * lp)460 lp_lock(struct lp_printer *lp)
461 {
462 	char path[PATH_MAX];
463 	struct stat st;
464         int fd, saved_errno;
465 
466 	if (lp->lp_lock) {
467 		errno = EWOULDBLOCK;
468 		return -1;
469 	}
470 
471 	if (fullpath(lp, LP_LO(lp), path, sizeof(path)) == -1) {
472 		log_warn("%s: %s", __func__, LP_LO(lp));
473 		return -1;
474 	}
475 
476         fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_EXLOCK|O_TRUNC,
477 	    0640);
478 	if (fd == -1) {
479 		if (errno != EWOULDBLOCK)
480 			log_warn("%s: open", __func__);
481 		return -1;
482 	}
483 
484 	if (fstat(fd, &st) == -1) {
485 		log_warn("%s: fstat", __func__);
486 		saved_errno = errno;
487 		(void)close(fd);
488 		errno = saved_errno;
489 		return -1;
490         }
491 
492 	if (!S_ISREG(st.st_mode)) {
493 		errno = EFTYPE;
494 		log_warnx("%s: %s: Not a regular file", __func__, path);
495 		(void)close(fd);
496 		return -1;
497 	}
498 
499 	if ((lp->lp_lock = fdopen(fd, "w")) == NULL) {
500 		log_warn("%s: fdopen", __func__);
501 		saved_errno = errno;
502 		(void)close(fd);
503 		errno = saved_errno;
504 		return -1;
505 	}
506 
507 	lp_setcurrtask(lp, NULL);
508 
509 	return 0;
510 }
511 
512 /*
513  * Truncate the lock file and close it.
514  */
515 void
lp_unlock(struct lp_printer * lp)516 lp_unlock(struct lp_printer *lp)
517 {
518 	if (ftruncate(fileno(lp->lp_lock), 0) == -1)
519 		log_warn("%s: ftruncate", __func__);
520 	if (fclose(lp->lp_lock) == EOF)
521 		log_warn("%s: fclose", __func__);
522 	lp->lp_lock = NULL;
523 }
524 
525 int
lp_getqueuestate(struct lp_printer * lp,int reset,int * qstate)526 lp_getqueuestate(struct lp_printer *lp, int reset, int *qstate)
527 {
528 	FILE *fp;
529 	struct stat st;
530 	int saved_errno;
531 
532 	*qstate = 0;
533 
534 	fp = lp->lp_lock;
535 	if (lp->lp_lock == NULL) {
536 		fp = lp_fopen(lp, LP_LO(lp));
537 		if (fp == NULL) {
538 			if (errno == ENOENT)
539 				return 0;
540 			log_warn("%s: lp_fopen", __func__);
541 			return -1;
542 		}
543 	}
544 
545 	if (fstat(fileno(fp), &st) == -1) {
546 		log_warn("%s: fstat", __func__);
547 		if (lp->lp_lock == NULL) {
548 			saved_errno = errno;
549 			(void)fclose(fp);
550 			errno = saved_errno;
551 		}
552 		return -1;
553 	}
554 
555 	if (st.st_mode & S_IXUSR)
556 		*qstate |= LPQ_PRINTER_DOWN;
557 	if (st.st_mode & S_IXGRP)
558 		*qstate |= LPQ_QUEUE_OFF;
559 	if (st.st_mode & S_IXOTH) {
560 		*qstate |= LPQ_QUEUE_UPDATED;
561 		if (reset) {
562 			st.st_mode &= ~S_IXOTH & 0777;
563 			if (fchmod(fileno(lp->lp_lock), st.st_mode) == -1)
564 				log_warn("%s: fchmod", __func__);
565 		}
566 	}
567 
568 	if (lp->lp_lock == NULL)
569 		fclose(fp);
570 
571 	return 0;
572 }
573 
574 /*
575  * Update the current task description in the lock file.
576  * The lock file must be opened.
577  */
578 void
lp_setcurrtask(struct lp_printer * lp,const char * cfile)579 lp_setcurrtask(struct lp_printer *lp, const char *cfile)
580 {
581 	int r;
582 
583 	if (ftruncate(fileno(lp->lp_lock), 0) == -1)
584 		log_warn("%s: ftruncate", __func__);
585 
586 	if (cfile)
587 		r = fprintf(lp->lp_lock, "%d\n%s\n", (int)getpid(), cfile);
588 	else
589 		r = fprintf(lp->lp_lock, "%d\n", (int)getpid());
590 	if (r < 0)
591 		log_warn("%s: fprintf", __func__);
592 
593 	if (fflush(lp->lp_lock) != 0)
594 		log_warn("%s: fflush", __func__);
595 }
596 
597 /*
598  * Find the pid of the running process if any, and the task being printed.
599  *
600  * Returns -1 on error (errno set).
601  *          0 if no process is running.
602  *          1 if a printer process is up.
603  *          2 if a printer process is up and a file is being printed.
604  */
605 int
lp_getcurrtask(struct lp_printer * lp,pid_t * ppid,char * dst,size_t dstsz)606 lp_getcurrtask(struct lp_printer *lp, pid_t *ppid, char *dst, size_t dstsz)
607 {
608 	FILE *fp;
609 	const char *errstr;
610 	char *line = NULL;
611 	size_t linesz = 0;
612 	ssize_t len;
613 	pid_t pid;
614 	int r, saved_errno;
615 
616 	pid = *ppid = 0;
617 	dst[0] = '\0';
618 	r = -1;
619 
620 	fp = lp_fopen(lp, LP_LO(lp));
621 	if (fp == NULL) {
622 		if (errno == ENOENT)
623 			return 0;
624 		log_warn("%s: lp_fopen", __func__);
625 		return -1;
626 	}
627 
628 	while ((len = getline(&line, &linesz, fp)) != -1) {
629 		if (line[len-1] == '\n')
630 			line[len-1] = '\0';
631 
632 		/* Read filename. */
633 		if (pid) {
634 			(void)strlcpy(dst, line, dstsz);
635 			break;
636 		}
637 
638 		pid = strtonum(line, 2, XXX_PID_MAX, &errstr);
639 		if (errstr) {
640 			log_warn("%s: strtonum", __func__);
641 			goto done;
642 		}
643 	}
644 
645 	if ((errno = ferror(fp))) {
646 		log_warn("%s: getline", __func__);
647 		goto done;
648 	}
649 
650 	r = 0;
651 	if (pid == 0)
652 		goto done;
653 
654 	if (kill(pid, 0) == -1 && errno != EPERM) {
655 		if (errno != ESRCH)
656 			log_warn("%s: kill", __func__);
657 		goto done;
658 	}
659 
660 	*ppid = pid;
661 	r = dst[0] ? 2 : 1;
662 
663     done:
664 	free(line);
665 	saved_errno = errno;
666 	(void)fclose(fp);
667 	errno = saved_errno;
668 	return r;
669 }
670 
671 /*
672  * Read the current printer status file.
673  * Return -1 on error, 0 on success.
674  */
675 int
lp_getstatus(struct lp_printer * lp,char * buf,size_t bufsz)676 lp_getstatus(struct lp_printer *lp, char *buf, size_t bufsz)
677 {
678 	size_t len;
679 	char *line;
680 	FILE *fp;
681 	int saved_errno;
682 
683 	buf[0] = '\0';
684 
685 	fp = lp_fopen(lp, LP_ST(lp));
686 	if (fp == NULL) {
687 		if (errno == ENOENT)
688 			return 0;
689 		log_warn("%s: lp_fopen", __func__);
690 		return -1;
691 	}
692 
693 	line = fgetln(fp, &len);
694 	if (line) {
695 		if (len >= bufsz)
696 			len = bufsz - 1;
697 		else if (line[len - 1] == '\n')
698 			len--;
699 		memmove(buf, line, len);
700 		buf[len] = '\0';
701 	}
702 	else if ((errno = ferror(fp))) {
703 		log_warn("%s: fgetln", __func__);
704 		saved_errno = errno;
705 		(void)fclose(fp);
706 		errno = saved_errno;
707 		return -1;
708 	}
709 
710 	(void)fclose(fp);
711 	return 0;
712 }
713 
714 /*
715  * Update the current printer status.
716  */
717 void
lp_setstatus(struct lp_printer * lp,const char * fmt,...)718 lp_setstatus(struct lp_printer *lp, const char *fmt, ...)
719 {
720 	va_list ap;
721 	FILE *fp;
722 	char path[PATH_MAX], *s;
723 	int fd = -1, r, saved_errno;
724 
725 	va_start(ap, fmt);
726 	r = vasprintf(&s, fmt, ap);
727 	va_end(ap);
728 
729 	if (r == -1) {
730 		log_warn("%s: vasprintf", __func__);
731 		return;
732 	}
733 
734 	if (fullpath(lp, LP_ST(lp), path, sizeof(path)) == -1) {
735 		log_warn("%s: fullpath", __func__);
736 		free(s);
737 		return;
738 	}
739 
740 	fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_EXLOCK|O_TRUNC, 0660);
741 	if (fd == -1) {
742 		log_warn("%s: open", __func__);
743 		free(s);
744 		return;
745 	}
746 
747 	fp = fdopen(fd, "w");
748 	if (fp == NULL) {
749 		log_warn("%s: fdopen", __func__);
750 		saved_errno = errno;
751 		(void)close(fd);
752 		free(s);
753 		errno = saved_errno;
754 		return;
755 	}
756 
757 	r = fprintf(fp, "%s\n", s);
758 
759 	if (r <= 0) {
760 		log_warn("%s: fprintf", __func__);
761 		saved_errno = errno;
762 		(void)fclose(fp);
763 		free(s);
764 		errno = saved_errno;
765 		return;
766 	}
767 
768 	(void)fclose(fp);
769 	free(s);
770 }
771 
772 /*
773  * Check that the given string is a valid filename for the spooler.
774  */
775 int
lp_validfilename(const char * fname,int cf)776 lp_validfilename(const char *fname, int cf)
777 {
778 	size_t len, i;
779 
780 	len = strlen(fname);
781 	if (len <= 6) /* strlen("cfA000") */
782 		return 0;
783 
784 	if (fname[0] != (cf ? 'c' : 'd') ||
785 	    fname[1] != 'f' ||
786 	    fname[2] < 'A' ||
787 	    fname[2] > 'Z' ||
788 	    !isdigit((unsigned char)fname[3]) ||
789 	    !isdigit((unsigned char)fname[4]) ||
790 	    !isdigit((unsigned char)fname[5]))
791 		return 0;
792 
793 	for (i = 6; i < len; i++)
794 		if (!isalpha((unsigned char)fname[i]) &&
795 		    !isdigit((unsigned char)fname[i]) &&
796 		    strchr("-_.", (unsigned char)fname[i]) == NULL)
797 			return 0;
798 
799 	return 1;
800 }
801 
802 /*
803  * Create a new control or data file in the printer spooldir.
804  * Control files have there name changed to a temporary name. They are renamed
805  * to their final name by lp_commit().
806  */
807 int
lp_create(struct lp_printer * lp,int cf,size_t sz,const char * fname)808 lp_create(struct lp_printer *lp, int cf, size_t sz, const char *fname)
809 {
810 	struct stat st;
811 	char path[PATH_MAX];
812 	int fd;
813 
814 	/* Make sure the file size is acceptable. */
815 	if (checksize(lp, sz) == -1)
816 		return -1;
817 
818 	if (fullpath(lp, fname, path, sizeof(path)) == -1) {
819 		log_warn("%s: %s", __func__, fname);
820 		return -1;
821 	}
822 
823 	if (cf) {
824 		/*
825 		 * Create a temporary file, but we want to avoid
826 		 * a collision with the final cf filename.
827 		 */
828 		/* XXX this would require a lock on .seq */
829 		path[strlen(LP_SD(lp)) + 1] = 'c';
830 		if (stat(path, &st) == 0) {
831 			errno = EEXIST;
832 			log_warn("%s: %s", __func__, fname);
833 			return -1;
834 		}
835 		path[strlen(LP_SD(lp)) + 1] = 't';
836 	}
837 
838 	fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0660);
839 	if (fd == -1)
840 		log_warn("%s: open", __func__);
841 
842 	return fd;
843 }
844 
845 /*
846  * Commit the job given by its temporary CF name.
847  * This is done by renaming the temporary CF file name to its final name.
848  * The functions return 0 on success, or -1 on error and set errno.
849  */
850 int
lp_commit(struct lp_printer * lp,const char * cf)851 lp_commit(struct lp_printer *lp, const char *cf)
852 {
853 	char ipath[PATH_MAX], opath[PATH_MAX];
854 
855 	if (fullpath(lp, cf, ipath, sizeof(ipath)) == -1 ||
856 	    fullpath(lp, cf, opath, sizeof(opath)) == -1)
857 		return -1;
858 
859 	ipath[strlen(LP_SD(lp)) + 1] = 't';
860 	opath[strlen(LP_SD(lp)) + 1] = 'c';
861 
862 	return rename(ipath, opath);
863 }
864 
865 /*
866  * Check if a file size is acceptable.
867  * Return -1 on error or if false (EFBIG or ENOSPC), 0 otherwise.
868  */
869 static int
checksize(struct lp_printer * lp,size_t sz)870 checksize(struct lp_printer *lp, size_t sz)
871 {
872 	struct statfs st;
873 	ssize_t len;
874 	size_t linesz = 0;
875 	off_t req, avail, minfree;
876 	char *line = NULL;
877 	const char *errstr;
878 	FILE *fp;
879 	int saved_errno;
880 
881 	if (sz == 0) {
882 		errno = EINVAL;
883 		return -1;
884 	}
885 
886 	/* Check printer limit. */
887 	if (lp->lp_mx && sz > (size_t)lp->lp_mx) {
888 		errno = EFBIG;
889 		return -1;
890 	}
891 
892 	/*
893 	 * Check for minfree.  Note that it does not really guarantee the
894 	 * directory will not be filled up anyway, since it's not taking
895 	 * other incoming files into account.
896 	 */
897 	fp = lp_fopen(lp, "minfree");
898 	if (fp == NULL) {
899 		if (errno == ENOENT)
900 			return 0;
901 		log_warn("%s: lp_fopen", __func__);
902 		return -1;
903 	}
904 
905 	len = getline(&line, &linesz, fp);
906 	saved_errno = errno;
907 	(void)fclose(fp);
908 	if (len == -1) {
909 		errno = saved_errno;
910 		return 0;
911 	}
912 
913 	if (line[len - 1] == '\n')
914 		line[len - 1] = '\0';
915 	minfree = strtonum(line, 0, INT_MAX, &errstr);
916 	free(line);
917 
918 	if (errstr)
919 		return 0;
920 
921 	if (statfs(LP_SD(lp), &st) == -1)
922 		return 0;
923 
924 	req = sz / 512 + (sz % 512) ? 1 : 0;
925 	avail = st.f_bavail * (st.f_bsize / 512);
926 	if (avail < minfree || (avail - minfree) < req) {
927 		errno = ENOSPC;
928 		return -1;
929 	}
930 
931 	return 0;
932 }
933