1 /* $OpenBSD: common.c,v 1.42 2021/01/19 09:04:13 claudio Exp $ */
2 /* $NetBSD: common.c,v 1.21 2000/08/09 14:28:50 itojun Exp $ */
3
4 /*
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
7 * (c) UNIX System Laboratories, Inc.
8 * All or some portions of this file are derived from material licensed
9 * to the University of California by American Telephone and Telegraph
10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 * the permission of UNIX System Laboratories, Inc.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #include <sys/stat.h>
39 #include <sys/time.h>
40
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45
46 #include <dirent.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <limits.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <signal.h>
55 #include <stdarg.h>
56 #include <ifaddrs.h>
57 #include "lp.h"
58 #include "pathnames.h"
59
60 /*
61 * Routines and data common to all the line printer functions.
62 */
63
64 char *AF; /* accounting file */
65 long BR; /* baud rate if lp is a tty */
66 char *CF; /* name of cifplot filter (per job) */
67 char *DF; /* name of tex filter (per job) */
68 long DU; /* daemon user-id */
69 char *FF; /* form feed string */
70 char *GF; /* name of graph(1G) filter (per job) */
71 long HL; /* print header last */
72 char *IF; /* name of input filter (created per job) */
73 char *LF; /* log file for error messages */
74 char *LO; /* lock file name */
75 char *LP; /* line printer device name */
76 long MC; /* maximum number of copies allowed */
77 char *MS; /* stty flags to set if lp is a tty */
78 long MX; /* maximum number of blocks to copy */
79 char *NF; /* name of ditroff filter (per job) */
80 char *OF; /* name of output filter (created once) */
81 long PL; /* page length */
82 long PW; /* page width */
83 long PX; /* page width in pixels */
84 long PY; /* page length in pixels */
85 char *RF; /* name of fortran text filter (per job) */
86 char *RG; /* restricted group */
87 char *RM; /* remote machine name */
88 char *RP; /* remote printer name */
89 long RS; /* restricted to those with local accounts */
90 long RW; /* open LP for reading and writing */
91 long SB; /* short banner instead of normal header */
92 long SC; /* suppress multiple copies */
93 char *SD; /* spool directory */
94 long SF; /* suppress FF on each print job */
95 long SH; /* suppress header page */
96 char *ST; /* status file name */
97 char *TF; /* name of troff filter (per job) */
98 char *TR; /* trailer string to be output when Q empties */
99 char *VF; /* name of vplot filter (per job) */
100
101 char line[BUFSIZ];
102 int remote; /* true if sending files to a remote host */
103
104 static int compar(const void *, const void *);
105
106 /*
107 * Create a TCP connection to host "rhost" at port "rport".
108 * If rport == 0, then use the printer service port.
109 * Most of this code comes from rcmd.c.
110 */
111 int
getport(char * rhost,int rport)112 getport(char *rhost, int rport)
113 {
114 struct addrinfo hints, *res, *r;
115 u_int timo = 1;
116 int s, lport = IPPORT_RESERVED - 1;
117 int error;
118 int refuse, trial;
119 char pbuf[NI_MAXSERV];
120
121 /*
122 * Get the host address and port number to connect to.
123 */
124 if (rhost == NULL)
125 fatal("no remote host to connect to");
126 memset(&hints, 0, sizeof(hints));
127 hints.ai_family = PF_UNSPEC;
128 hints.ai_socktype = SOCK_STREAM;
129 if (rport)
130 snprintf(pbuf, sizeof(pbuf), "%d", rport);
131 else
132 snprintf(pbuf, sizeof(pbuf), "printer");
133 siginterrupt(SIGINT, 1);
134 error = getaddrinfo(rhost, pbuf, &hints, &res);
135 siginterrupt(SIGINT, 0);
136 if (error)
137 fatal("printer/tcp: %s", gai_strerror(error));
138
139 /*
140 * Try connecting to the server.
141 */
142 retry:
143 s = -1;
144 refuse = trial = 0;
145 for (r = res; r; r = r->ai_next) {
146 trial++;
147 retryport:
148 PRIV_START;
149 s = rresvport_af(&lport, r->ai_family);
150 PRIV_END;
151 if (s < 0) {
152 /* fall back to non-privileged port */
153 if (errno != EACCES ||
154 (s = socket(r->ai_family, SOCK_STREAM, 0)) < 0) {
155 freeaddrinfo(res);
156 return(-1);
157 }
158 }
159 siginterrupt(SIGINT, 1);
160 if (connect(s, r->ai_addr, r->ai_addrlen) < 0) {
161 error = errno;
162 siginterrupt(SIGINT, 0);
163 (void)close(s);
164 s = -1;
165 errno = error;
166 if (errno == EADDRINUSE) {
167 lport--;
168 goto retryport;
169 } else if (errno == ECONNREFUSED)
170 refuse++;
171 continue;
172 } else {
173 siginterrupt(SIGINT, 0);
174 break;
175 }
176 }
177 if (s < 0 && trial == refuse && timo <= 16) {
178 sleep(timo);
179 timo *= 2;
180 goto retry;
181 }
182 if (res)
183 freeaddrinfo(res);
184
185 /* Don't worry if we get an error from setsockopt(). */
186 trial = 1;
187 setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &trial, sizeof(trial));
188
189 return(s);
190 }
191
192 /*
193 * Getline reads a line from the control file cfp, removes tabs, converts
194 * new-line to null and leaves it in line.
195 * Returns 0 at EOF or the number of characters read.
196 */
197 int
get_line(FILE * cfp)198 get_line(FILE *cfp)
199 {
200 int linel = 0;
201 char *lp = line;
202 int c;
203
204 while ((c = getc(cfp)) != '\n' && linel+1<sizeof(line)) {
205 if (c == EOF)
206 return(0);
207 if (c == '\t') {
208 do {
209 *lp++ = ' ';
210 linel++;
211 } while ((linel & 07) != 0 && linel+1 < sizeof(line));
212 continue;
213 }
214 *lp++ = c;
215 linel++;
216 }
217 *lp++ = '\0';
218 return(linel);
219 }
220
221 /*
222 * Scan the current directory and make a list of daemon files sorted by
223 * creation time.
224 * Return the number of entries and a pointer to the list.
225 */
226 int
getq(struct queue *** namelist)227 getq(struct queue ***namelist)
228 {
229 struct dirent *d;
230 struct queue *q, **queue = NULL;
231 size_t nitems = 0, arraysz;
232 struct stat stbuf;
233 DIR *dirp;
234
235 PRIV_START;
236 dirp = opendir(SD);
237 PRIV_END;
238 if (dirp == NULL)
239 return(-1);
240 if (fstat(dirfd(dirp), &stbuf) < 0)
241 goto errdone;
242
243 /*
244 * Estimate the array size by taking the size of the directory file
245 * and dividing it by a multiple of the minimum size entry.
246 */
247 arraysz = (stbuf.st_size / 24);
248 queue = calloc(arraysz, sizeof(struct queue *));
249 if (queue == NULL)
250 goto errdone;
251
252 while ((d = readdir(dirp)) != NULL) {
253 if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
254 continue; /* daemon control files only */
255 PRIV_START;
256 if (stat(d->d_name, &stbuf) < 0) {
257 PRIV_END;
258 continue; /* Doesn't exist */
259 }
260 PRIV_END;
261 q = malloc(sizeof(struct queue));
262 if (q == NULL)
263 goto errdone;
264 q->q_time = stbuf.st_mtime;
265 strlcpy(q->q_name, d->d_name, sizeof(q->q_name));
266
267 /*
268 * Check to make sure the array has space left and
269 * realloc the maximum size.
270 */
271 if (nitems == arraysz) {
272 struct queue **newqueue;
273 newqueue = reallocarray(queue,
274 arraysz, 2 * sizeof(struct queue *));
275 if (newqueue == NULL) {
276 free(q);
277 goto errdone;
278 }
279 arraysz *= 2;
280 queue = newqueue;
281 }
282 queue[nitems++] = q;
283 }
284 closedir(dirp);
285 if (nitems)
286 qsort(queue, nitems, sizeof(struct queue *), compar);
287 *namelist = queue;
288 return(nitems);
289
290 errdone:
291 if (queue != NULL) {
292 while (nitems--)
293 free(queue[nitems]);
294 free(queue);
295 }
296 closedir(dirp);
297 return(-1);
298 }
299
300 /*
301 * Compare modification times.
302 */
303 static int
compar(const void * v1,const void * v2)304 compar(const void *v1, const void *v2)
305 {
306 struct queue *p1 = *(struct queue **)v1;
307 struct queue *p2 = *(struct queue **)v2;
308
309 return(p1->q_time - p2->q_time);
310 }
311
312 /*
313 * Figure out whether the local machine is the same
314 * as the remote machine (RM) entry (if it exists).
315 */
316 char *
checkremote(void)317 checkremote(void)
318 {
319 char lname[NI_MAXHOST], rname[NI_MAXHOST];
320 struct addrinfo hints, *res, *res0;
321 static char errbuf[128];
322 int error;
323 struct ifaddrs *ifap, *ifa;
324 const int niflags = NI_NUMERICHOST;
325 struct sockaddr *sa;
326 #ifdef __KAME__
327 struct sockaddr_in6 sin6;
328 struct sockaddr_in6 *sin6p;
329 #endif
330
331 remote = 0; /* assume printer is local on failure */
332
333 if (RM == NULL || *RM == '\0')
334 return NULL;
335
336 /* get the local interface addresses */
337 siginterrupt(SIGINT, 1);
338 if (getifaddrs(&ifap) < 0) {
339 (void)snprintf(errbuf, sizeof(errbuf),
340 "unable to get local interface address: %s",
341 strerror(errno));
342 siginterrupt(SIGINT, 0);
343 return errbuf;
344 }
345 siginterrupt(SIGINT, 0);
346
347 /* get the remote host addresses (RM) */
348 memset(&hints, 0, sizeof(hints));
349 hints.ai_flags = AI_CANONNAME;
350 hints.ai_family = PF_UNSPEC;
351 hints.ai_socktype = SOCK_STREAM;
352 res = NULL;
353 siginterrupt(SIGINT, 1);
354 error = getaddrinfo(RM, NULL, &hints, &res0);
355 siginterrupt(SIGINT, 0);
356 if (error) {
357 (void)snprintf(errbuf, sizeof(errbuf),
358 "unable to resolve remote machine %s: %s",
359 RM, gai_strerror(error));
360 freeifaddrs(ifap);
361 return errbuf;
362 }
363
364 remote = 1; /* assume printer is remote */
365
366 for (res = res0; res; res = res->ai_next) {
367 siginterrupt(SIGINT, 1);
368 error = getnameinfo(res->ai_addr, res->ai_addrlen,
369 rname, sizeof(rname), NULL, 0, niflags);
370 siginterrupt(SIGINT, 0);
371 if (error != 0)
372 continue;
373 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
374 sa = ifa->ifa_addr;
375 #ifdef __KAME__
376 sin6p = (struct sockaddr_in6 *)sa;
377 if (sa->sa_family == AF_INET6 &&
378 sa->sa_len == sizeof(sin6) &&
379 IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr) &&
380 *(u_int16_t *)&sin6p->sin6_addr.s6_addr[2]) {
381 /* kame scopeid hack */
382 memcpy(&sin6, ifa->ifa_addr, sizeof(sin6));
383 sin6.sin6_scope_id =
384 ntohs(*(u_int16_t *)&sin6p->sin6_addr.s6_addr[2]);
385 sin6.sin6_addr.s6_addr[2] = 0;
386 sin6.sin6_addr.s6_addr[3] = 0;
387 sa = (struct sockaddr *)&sin6;
388 }
389 #endif
390 siginterrupt(SIGINT, 1);
391 error = getnameinfo(sa, sa->sa_len,
392 lname, sizeof(lname), NULL, 0, niflags);
393 siginterrupt(SIGINT, 0);
394 if (error != 0)
395 continue;
396
397 if (strcmp(rname, lname) == 0) {
398 remote = 0;
399 goto done;
400 }
401 }
402 }
403 done:
404 freeaddrinfo(res0);
405 freeifaddrs(ifap);
406 return NULL;
407 }
408
409 __dead void
fatal(const char * msg,...)410 fatal(const char *msg, ...)
411 {
412 extern char *__progname;
413 va_list ap;
414
415 va_start(ap, msg);
416 if (from != host)
417 (void)printf("%s: ", host);
418 (void)printf("%s: ", __progname);
419 if (printer)
420 (void)printf("%s: ", printer);
421 (void)vprintf(msg, ap);
422 va_end(ap);
423 (void)putchar('\n');
424 exit(1);
425 }
426
427 int
safe_open(const char * path,int flags,mode_t mode)428 safe_open(const char *path, int flags, mode_t mode)
429 {
430 int fd, serrno;
431 struct stat stbuf;
432
433 if ((fd = open(path, flags|O_NONBLOCK, mode)) < 0 ||
434 fstat(fd, &stbuf) < 0) {
435 if (fd >= 0) {
436 serrno = errno;
437 close(fd);
438 errno = serrno;
439 }
440 return (-1);
441 }
442 if (!S_ISREG(stbuf.st_mode)) {
443 close(fd);
444 errno = EACCES;
445 return (-1);
446 }
447 if (mode)
448 (void)fchmod(fd, mode);
449 return (fd);
450 }
451
452 /*
453 * Make sure there's some work to do before forking off a child - lpd
454 * Check to see if anything in queue - lpq
455 */
456 int
ckqueue(char * cap)457 ckqueue(char *cap)
458 {
459 struct dirent *d;
460 DIR *dirp;
461 char *spooldir;
462
463 if (cgetstr(cap, "sd", &spooldir) >= 0) {
464 dirp = opendir(spooldir);
465 free(spooldir);
466 } else
467 dirp = opendir(_PATH_DEFSPOOL);
468
469 if (dirp == NULL)
470 return (-1);
471 while ((d = readdir(dirp)) != NULL) {
472 if (d->d_name[0] == 'c' && d->d_name[1] == 'f') {
473 closedir(dirp);
474 return (1); /* found a cf file */
475 }
476 }
477 closedir(dirp);
478 return (0);
479 }
480