1 /*
2 * Copyright (c) 1983, 1993, 1994
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. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * @(#) Copyright (c) 1983, 1993, 1994 The Regents of the University of California. All rights reserved.
31 * @(#)lpd.c 8.7 (Berkeley) 5/10/95
32 * $FreeBSD: src/usr.sbin/lpr/lpd/lpd.c,v 1.12.2.22 2002/06/30 04:09:11 gad Exp $
33 */
34
35 /*
36 * lpd -- line printer daemon.
37 *
38 * Listen for a connection and perform the requested operation.
39 * Operations are:
40 * \1printer\n
41 * check the queue for jobs and print any found.
42 * \2printer\n
43 * receive a job from another machine and queue it.
44 * \3printer [users ...] [jobs ...]\n
45 * return the current state of the queue (short form).
46 * \4printer [users ...] [jobs ...]\n
47 * return the current state of the queue (long form).
48 * \5printer person [users ...] [jobs ...]\n
49 * remove jobs from the queue.
50 *
51 * Strategy to maintain protected spooling area:
52 * 1. Spooling area is writable only by daemon and spooling group
53 * 2. lpr runs setuid root and setgrp spooling group; it uses
54 * root to access any file it wants (verifying things before
55 * with an access call) and group id to know how it should
56 * set up ownership of files in the spooling area.
57 * 3. Files in spooling area are owned by root, group spooling
58 * group, with mode 660.
59 * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
60 * access files and printer. Users can't get to anything
61 * w/o help of lpq and lprm programs.
62 */
63
64 #include <sys/param.h>
65 #include <sys/wait.h>
66 #include <sys/types.h>
67 #include <sys/socket.h>
68 #include <sys/un.h>
69 #include <sys/stat.h>
70 #include <sys/file.h>
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
73
74 #include <netdb.h>
75 #include <unistd.h>
76 #include <syslog.h>
77 #include <signal.h>
78 #include <err.h>
79 #include <errno.h>
80 #include <fcntl.h>
81 #include <dirent.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <string.h>
85 #include <sysexits.h>
86 #include <ctype.h>
87 #include "lp.h"
88 #include "lp.local.h"
89 #include "pathnames.h"
90 #include "extern.h"
91
92 int lflag; /* log requests flag */
93 int sflag; /* no incoming port flag */
94 int from_remote; /* from remote socket */
95
96 static void reapchild(int _signo);
97 static void mcleanup(int _signo);
98 static void doit(void);
99 static void startup(void);
100 static void chkhost(struct sockaddr *_f, int _ch_opts);
101 static int ckqueue(struct printer *_pp);
102 static void fhosterr(int _ch_opts, char *_sysmsg, char *_usermsg);
103 static int *socksetup(int _af, int _debuglvl);
104 static void usage(void);
105
106 /* XXX from libc/net/rcmd.c */
107 extern int __ivaliduser_sa(FILE *, struct sockaddr *, socklen_t,
108 const char *, const char *);
109
110 uid_t uid, euid;
111
112 #define LPD_NOPORTCHK 0001 /* skip reserved-port check */
113 #define LPD_LOGCONNERR 0002 /* (sys)log connection errors */
114 #define LPD_ADDFROMLINE 0004 /* just used for fhosterr() */
115
116 int
main(int argc,char ** argv)117 main(int argc, char **argv)
118 {
119 int ch_options, errs, f, funix, *finet, i, lfd, socket_debug;
120 fd_set defreadfds;
121 struct sockaddr_un un, fromunix;
122 struct sockaddr_storage frominet;
123 socklen_t fromlen;
124 sigset_t omask, nmask;
125 struct servent *sp, serv;
126 int inet_flag = 0, inet6_flag = 0;
127
128 euid = geteuid(); /* these shouldn't be different */
129 uid = getuid();
130
131 ch_options = 0;
132 socket_debug = 0;
133 gethostname(local_host, sizeof(local_host));
134
135 progname = "lpd";
136
137 if (euid != 0)
138 errx(EX_NOPERM,"must run as root");
139
140 errs = 0;
141 while ((i = getopt(argc, argv, "cdlpswW46")) != -1)
142 switch (i) {
143 case 'c':
144 /* log all kinds of connection-errors to syslog */
145 ch_options |= LPD_LOGCONNERR;
146 break;
147 case 'd':
148 socket_debug++;
149 break;
150 case 'l':
151 lflag++;
152 break;
153 case 'p': /* letter initially used for -s */
154 /*
155 * This will probably be removed with 5.0-release.
156 */
157 /* FALLTHROUGH */
158 case 's': /* secure (no inet) */
159 sflag++;
160 break;
161 case 'w': /* netbsd uses -w for maxwait */
162 /*
163 * This will be removed after the release of 4.4, as
164 * it conflicts with -w in netbsd's lpd. For now it
165 * is just a warning, so we won't suddenly break lpd
166 * for anyone who is currently using the option.
167 */
168 syslog(LOG_WARNING,
169 "NOTE: the -w option has been renamed -W");
170 syslog(LOG_WARNING,
171 "NOTE: please change your lpd config to use -W");
172 /* FALLTHROUGH */
173 case 'W':
174 /* allow connections coming from a non-reserved port */
175 /* (done by some lpr-implementations for MS-Windows) */
176 ch_options |= LPD_NOPORTCHK;
177 break;
178 case '4':
179 family = PF_INET;
180 inet_flag++;
181 break;
182 case '6':
183 #ifdef INET6
184 family = PF_INET6;
185 inet6_flag++;
186 #else
187 errx(EX_USAGE, "lpd compiled sans INET6 (IPv6 support)");
188 #endif
189 break;
190 /*
191 * The following options are not in FreeBSD (yet?), but are
192 * listed here to "reserve" them, because the option-letters
193 * are used by either NetBSD or OpenBSD (as of July 2001).
194 */
195 case 'b': /* set bind-addr */
196 case 'n': /* set max num of children */
197 case 'r': /* allow 'of' for remote ptrs */
198 /* ...[not needed in freebsd] */
199 /* FALLTHROUGH */
200 default:
201 errs++;
202 }
203 if (inet_flag && inet6_flag)
204 family = PF_UNSPEC;
205 argc -= optind;
206 argv += optind;
207 if (errs)
208 usage();
209
210 if (argc == 1) {
211 if ((i = atoi(argv[0])) == 0)
212 usage();
213 if (i < 0 || i > USHRT_MAX)
214 errx(EX_USAGE, "port # %d is invalid", i);
215
216 serv.s_port = htons(i);
217 sp = &serv;
218 argc--;
219 } else {
220 sp = getservbyname("printer", "tcp");
221 if (sp == NULL)
222 errx(EX_OSFILE, "printer/tcp: unknown service");
223 }
224
225 if (argc != 0)
226 usage();
227
228 /*
229 * We run chkprintcap right away to catch any errors and blat them
230 * to stderr while we still have it open, rather than sending them
231 * to syslog and leaving the user wondering why lpd started and
232 * then stopped. There should probably be a command-line flag to
233 * ignore errors from chkprintcap.
234 */
235 {
236 pid_t pid;
237 int status;
238 pid = fork();
239 if (pid < 0) {
240 err(EX_OSERR, "cannot fork");
241 } else if (pid == 0) { /* child */
242 execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, NULL);
243 err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP);
244 }
245 if (waitpid(pid, &status, 0) < 0) {
246 err(EX_OSERR, "cannot wait");
247 }
248 if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
249 errx(EX_OSFILE, "%d errors in printcap file, exiting",
250 WEXITSTATUS(status));
251 }
252
253 #ifndef DEBUG
254 /*
255 * Set up standard environment by detaching from the parent.
256 */
257 daemon(0, 0);
258 #endif
259
260 openlog("lpd", LOG_PID, LOG_LPR);
261 syslog(LOG_INFO, "lpd startup: logging=%d%s%s", lflag,
262 socket_debug ? " dbg" : "", sflag ? " net-secure" : "");
263 umask(0);
264 /*
265 * NB: This depends on O_NONBLOCK semantics doing the right thing;
266 * i.e., applying only to the O_EXLOCK and not to the rest of the
267 * open/creation. As of 1997-12-02, this is the case for commonly-
268 * used filesystems. There are other places in this code which
269 * make the same assumption.
270 */
271 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
272 LOCK_FILE_MODE);
273 if (lfd < 0) {
274 if (errno == EWOULDBLOCK) /* active daemon present */
275 exit(0);
276 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
277 exit(1);
278 }
279 fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */
280 ftruncate(lfd, 0);
281 /*
282 * write process id for others to know
283 */
284 sprintf(line, "%u\n", getpid());
285 f = strlen(line);
286 if (write(lfd, line, f) != f) {
287 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
288 exit(1);
289 }
290 signal(SIGCHLD, reapchild);
291 /*
292 * Restart all the printers.
293 */
294 startup();
295 unlink(_PATH_SOCKETNAME);
296 funix = socket(AF_UNIX, SOCK_STREAM, 0);
297 if (funix < 0) {
298 syslog(LOG_ERR, "socket: %m");
299 exit(1);
300 }
301
302 sigemptyset(&nmask);
303 sigaddset(&nmask, SIGHUP);
304 sigaddset(&nmask, SIGINT);
305 sigaddset(&nmask, SIGQUIT);
306 sigaddset(&nmask, SIGTERM);
307 sigprocmask(SIG_BLOCK, &nmask, &omask);
308
309 umask(07);
310 signal(SIGHUP, mcleanup);
311 signal(SIGINT, mcleanup);
312 signal(SIGQUIT, mcleanup);
313 signal(SIGTERM, mcleanup);
314 memset(&un, 0, sizeof(un));
315 un.sun_family = AF_UNIX;
316 strcpy(un.sun_path, _PATH_SOCKETNAME);
317 #ifndef SUN_LEN
318 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
319 #endif
320 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
321 syslog(LOG_ERR, "ubind: %m");
322 exit(1);
323 }
324 umask(0);
325 sigprocmask(SIG_SETMASK, &omask, NULL);
326 FD_ZERO(&defreadfds);
327 FD_SET(funix, &defreadfds);
328 listen(funix, 5);
329 if (sflag == 0) {
330 finet = socksetup(family, socket_debug);
331 } else
332 finet = NULL; /* pretend we couldn't open TCP socket. */
333 if (finet) {
334 for (i = 1; i <= *finet; i++) {
335 FD_SET(finet[i], &defreadfds);
336 listen(finet[i], 5);
337 }
338 }
339 /*
340 * Main loop: accept, do a request, continue.
341 */
342 memset(&frominet, 0, sizeof(frominet));
343 memset(&fromunix, 0, sizeof(fromunix));
344 if (lflag)
345 syslog(LOG_INFO, "lpd startup: ready to accept requests");
346 /*
347 * XXX - should be redone for multi-protocol
348 */
349 for (;;) {
350 int domain, nfds, s;
351 fd_set readfds;
352
353 FD_COPY(&defreadfds, &readfds);
354 nfds = select(20, &readfds, 0, 0, 0);
355 if (nfds <= 0) {
356 if (nfds < 0 && errno != EINTR)
357 syslog(LOG_WARNING, "select: %m");
358 continue;
359 }
360 domain = -1; /* avoid compile-time warning */
361 s = -1; /* avoid compile-time warning */
362 if (FD_ISSET(funix, &readfds)) {
363 domain = AF_UNIX, fromlen = sizeof(fromunix);
364 s = accept(funix,
365 (struct sockaddr *)&fromunix, &fromlen);
366 } else {
367 for (i = 1; i <= *finet; i++)
368 if (FD_ISSET(finet[i], &readfds)) {
369 domain = AF_INET;
370 fromlen = sizeof(frominet);
371 s = accept(finet[i],
372 (struct sockaddr *)&frominet,
373 &fromlen);
374 }
375 }
376 if (s < 0) {
377 if (errno != EINTR)
378 syslog(LOG_WARNING, "accept: %m");
379 continue;
380 }
381 if (fork() == 0) {
382 /*
383 * Note that printjob() also plays around with
384 * signal-handling routines, and may need to be
385 * changed when making changes to signal-handling.
386 */
387 signal(SIGCHLD, SIG_DFL);
388 signal(SIGHUP, SIG_IGN);
389 signal(SIGINT, SIG_IGN);
390 signal(SIGQUIT, SIG_IGN);
391 signal(SIGTERM, SIG_IGN);
392 close(funix);
393 if (sflag == 0 && finet) {
394 for (i = 1; i <= *finet; i++)
395 close(finet[i]);
396 }
397 dup2(s, 1);
398 close(s);
399 if (domain == AF_INET) {
400 /* for both AF_INET and AF_INET6 */
401 from_remote = 1;
402 chkhost((struct sockaddr *)&frominet,
403 ch_options);
404 } else
405 from_remote = 0;
406 doit();
407 exit(0);
408 }
409 close(s);
410 }
411 }
412
413 static void
reapchild(int signo __unused)414 reapchild(int signo __unused)
415 {
416 int status;
417
418 while (wait3(&status, WNOHANG, 0) > 0)
419 ;
420 }
421
422 static void
mcleanup(int signo)423 mcleanup(int signo)
424 {
425 /*
426 * XXX syslog(3) is not signal-safe.
427 */
428 if (lflag) {
429 if (signo)
430 syslog(LOG_INFO, "exiting on signal %d", signo);
431 else
432 syslog(LOG_INFO, "exiting");
433 }
434 unlink(_PATH_SOCKETNAME);
435 exit(0);
436 }
437
438 /*
439 * Stuff for handling job specifications
440 */
441 char *user[MAXUSERS]; /* users to process */
442 int users; /* # of users in user array */
443 int requ[MAXREQUESTS]; /* job number of spool entries */
444 int requests; /* # of spool requests */
445 char *person; /* name of person doing lprm */
446
447 /* buffer to hold the client's machine-name */
448 static char frombuf[MAXHOSTNAMELEN];
449 char cbuf[BUFSIZ]; /* command line buffer */
450 const char *cmdnames[] = {
451 "null",
452 "printjob",
453 "recvjob",
454 "displayq short",
455 "displayq long",
456 "rmjob"
457 };
458
459 static void
doit(void)460 doit(void)
461 {
462 char *cp, *printer;
463 int n;
464 int status;
465 struct printer myprinter, *pp = &myprinter;
466
467 init_printer(&myprinter);
468
469 for (;;) {
470 cp = cbuf;
471 do {
472 if (cp >= &cbuf[sizeof(cbuf) - 1])
473 fatal(0, "Command line too long");
474 if ((n = read(STDOUT_FILENO, cp, 1)) != 1) {
475 if (n < 0)
476 fatal(0, "Lost connection");
477 return;
478 }
479 } while (*cp++ != '\n');
480 *--cp = '\0';
481 cp = cbuf;
482 if (lflag) {
483 if (*cp >= '\1' && *cp <= '\5')
484 syslog(LOG_INFO, "%s requests %s %s",
485 from_host, cmdnames[(u_char)*cp], cp+1);
486 else
487 syslog(LOG_INFO, "bad request (%d) from %s",
488 *cp, from_host);
489 }
490 switch (*cp++) {
491 case CMD_CHECK_QUE: /* check the queue, print any jobs there */
492 startprinting(cp);
493 break;
494 case CMD_TAKE_THIS: /* receive files to be queued */
495 if (!from_remote) {
496 syslog(LOG_INFO, "illegal request (%d)", *cp);
497 exit(1);
498 }
499 recvjob(cp);
500 break;
501 case CMD_SHOWQ_SHORT: /* display the queue (short form) */
502 case CMD_SHOWQ_LONG: /* display the queue (long form) */
503 /* XXX - this all needs to be redone. */
504 printer = cp;
505 while (*cp) {
506 if (*cp != ' ') {
507 cp++;
508 continue;
509 }
510 *cp++ = '\0';
511 while (isspace(*cp))
512 cp++;
513 if (*cp == '\0')
514 break;
515 if (isdigit(*cp)) {
516 if (requests >= MAXREQUESTS)
517 fatal(0, "Too many requests");
518 requ[requests++] = atoi(cp);
519 } else {
520 if (users >= MAXUSERS)
521 fatal(0, "Too many users");
522 user[users++] = cp;
523 }
524 }
525 status = getprintcap(printer, pp);
526 if (status < 0)
527 fatal(pp, "%s", pcaperr(status));
528 displayq(pp, cbuf[0] == CMD_SHOWQ_LONG);
529 exit(0);
530 case CMD_RMJOB: /* remove a job from the queue */
531 if (!from_remote) {
532 syslog(LOG_INFO, "illegal request (%d)", *cp);
533 exit(1);
534 }
535 printer = cp;
536 while (*cp && *cp != ' ')
537 cp++;
538 if (!*cp)
539 break;
540 *cp++ = '\0';
541 person = cp;
542 while (*cp) {
543 if (*cp != ' ') {
544 cp++;
545 continue;
546 }
547 *cp++ = '\0';
548 while (isspace(*cp))
549 cp++;
550 if (*cp == '\0')
551 break;
552 if (isdigit(*cp)) {
553 if (requests >= MAXREQUESTS)
554 fatal(0, "Too many requests");
555 requ[requests++] = atoi(cp);
556 } else {
557 if (users >= MAXUSERS)
558 fatal(0, "Too many users");
559 user[users++] = cp;
560 }
561 }
562 rmjob(printer);
563 break;
564 }
565 fatal(0, "Illegal service request");
566 }
567 }
568
569 /*
570 * Make a pass through the printcap database and start printing any
571 * files left from the last time the machine went down.
572 */
573 static void
startup(void)574 startup(void)
575 {
576 int pid, status, more;
577 struct printer myprinter, *pp = &myprinter;
578
579 more = firstprinter(pp, &status);
580 if (status)
581 goto errloop;
582 while (more) {
583 if (ckqueue(pp) <= 0) {
584 goto next;
585 }
586 if (lflag)
587 syslog(LOG_INFO, "lpd startup: work for %s",
588 pp->printer);
589 if ((pid = fork()) < 0) {
590 syslog(LOG_WARNING, "lpd startup: cannot fork for %s",
591 pp->printer);
592 mcleanup(0);
593 }
594 if (pid == 0) {
595 lastprinter();
596 printjob(pp);
597 /* NOTREACHED */
598 }
599 do {
600 next:
601 more = nextprinter(pp, &status);
602 errloop:
603 if (status)
604 syslog(LOG_WARNING,
605 "lpd startup: printcap entry for %s has errors, skipping",
606 pp->printer ? pp->printer : "<noname?>");
607 } while (more && status);
608 }
609 }
610
611 /*
612 * Make sure there's some work to do before forking off a child
613 */
614 static int
ckqueue(struct printer * pp)615 ckqueue(struct printer *pp)
616 {
617 struct dirent *d;
618 DIR *dirp;
619 char *spooldir;
620
621 spooldir = pp->spool_dir;
622 if ((dirp = opendir(spooldir)) == NULL)
623 return (-1);
624 while ((d = readdir(dirp)) != NULL) {
625 if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
626 continue; /* daemon control files only */
627 closedir(dirp);
628 return (1); /* found something */
629 }
630 closedir(dirp);
631 return (0);
632 }
633
634 #define DUMMY ":nobody::"
635
636 /*
637 * Check to see if the host connecting to this host has access to any
638 * lpd services on this host.
639 */
640 static void
chkhost(struct sockaddr * f,int ch_opts)641 chkhost(struct sockaddr *f, int ch_opts)
642 {
643 struct addrinfo hints, *res, *r;
644 FILE *hostf;
645 char hostbuf[NI_MAXHOST], ip[NI_MAXHOST];
646 char serv[NI_MAXSERV];
647 char *syserr, *usererr;
648 int error, errsav, fpass, good, wantsl;
649
650 wantsl = 0;
651 if (ch_opts & LPD_LOGCONNERR)
652 wantsl = 1; /* also syslog the errors */
653
654 from_host = ".na.";
655
656 /* Need real hostname for temporary filenames */
657 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0,
658 NI_NAMEREQD);
659 if (error) {
660 errsav = error;
661 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf),
662 NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
663 if (error) {
664 asprintf(&syserr,
665 "can not determine hostname for remote host (%d,%d)",
666 errsav, error);
667 asprintf(&usererr,
668 "Host name for your address is not known");
669 fhosterr(ch_opts, syserr, usererr);
670 /* NOTREACHED */
671 }
672 asprintf(&syserr,
673 "Host name for remote host (%s) not known (%d)",
674 hostbuf, errsav);
675 asprintf(&usererr,
676 "Host name for your address (%s) is not known",
677 hostbuf);
678 fhosterr(ch_opts, syserr, usererr);
679 /* NOTREACHED */
680 }
681
682 strlcpy(frombuf, hostbuf, sizeof(frombuf));
683 from_host = frombuf;
684 ch_opts |= LPD_ADDFROMLINE;
685
686 /* Need address in stringform for comparison (no DNS lookup here) */
687 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0,
688 NI_NUMERICHOST | NI_WITHSCOPEID);
689 if (error) {
690 asprintf(&syserr, "Cannot print IP address (error %d)",
691 error);
692 asprintf(&usererr, "Cannot print IP address for your host");
693 fhosterr(ch_opts, syserr, usererr);
694 /* NOTREACHED */
695 }
696 from_ip = strdup(hostbuf);
697
698 /* Reject numeric addresses */
699 memset(&hints, 0, sizeof(hints));
700 hints.ai_family = family;
701 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
702 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
703 if (getaddrinfo(from_host, NULL, &hints, &res) == 0) {
704 freeaddrinfo(res);
705 /* This syslog message already includes from_host */
706 ch_opts &= ~LPD_ADDFROMLINE;
707 asprintf(&syserr, "reverse lookup results in non-FQDN %s",
708 from_host);
709 /* same message to both syslog and remote user */
710 fhosterr(ch_opts, syserr, syserr);
711 /* NOTREACHED */
712 }
713
714 /* Check for spoof, ala rlogind */
715 memset(&hints, 0, sizeof(hints));
716 hints.ai_family = family;
717 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
718 error = getaddrinfo(from_host, NULL, &hints, &res);
719 if (error) {
720 asprintf(&syserr, "dns lookup for address %s failed: %s",
721 from_ip, gai_strerror(error));
722 asprintf(&usererr, "hostname for your address (%s) unknown: %s",
723 from_ip, gai_strerror(error));
724 fhosterr(ch_opts, syserr, usererr);
725 /* NOTREACHED */
726 }
727 good = 0;
728 for (r = res; good == 0 && r; r = r->ai_next) {
729 error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip),
730 NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
731 if (!error && !strcmp(from_ip, ip))
732 good = 1;
733 }
734 if (res)
735 freeaddrinfo(res);
736 if (good == 0) {
737 asprintf(&syserr, "address for remote host (%s) not matched",
738 from_ip);
739 asprintf(&usererr,
740 "address for your hostname (%s) not matched", from_ip);
741 fhosterr(ch_opts, syserr, usererr);
742 /* NOTREACHED */
743 }
744
745 fpass = 1;
746 hostf = fopen(_PATH_HOSTSEQUIV, "r");
747 again:
748 if (hostf) {
749 if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) {
750 fclose(hostf);
751 goto foundhost;
752 }
753 fclose(hostf);
754 }
755 if (fpass == 1) {
756 fpass = 2;
757 hostf = fopen(_PATH_HOSTSLPD, "r");
758 goto again;
759 }
760 /* This syslog message already includes from_host */
761 ch_opts &= ~LPD_ADDFROMLINE;
762 asprintf(&syserr, "refused connection from %s, sip=%s", from_host,
763 from_ip);
764 asprintf(&usererr,
765 "Print-services are not available to your host (%s).", from_host);
766 fhosterr(ch_opts, syserr, usererr);
767 /* NOTREACHED */
768
769 foundhost:
770 if (ch_opts & LPD_NOPORTCHK)
771 return; /* skip the reserved-port check */
772
773 error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv),
774 NI_NUMERICSERV);
775 if (error) {
776 /* same message to both syslog and remote user */
777 asprintf(&syserr, "malformed from-address (%d)", error);
778 fhosterr(ch_opts, syserr, syserr);
779 /* NOTREACHED */
780 }
781
782 if (atoi(serv) >= IPPORT_RESERVED) {
783 /* same message to both syslog and remote user */
784 asprintf(&syserr, "connected from invalid port (%s)", serv);
785 fhosterr(ch_opts, syserr, syserr);
786 /* NOTREACHED */
787 }
788 }
789
790 /*
791 * Handle fatal errors in chkhost. The first message will optionally be
792 * sent to syslog, the second one is sent to the connecting host.
793 *
794 * The idea is that the syslog message is meant for an administrator of a
795 * print server (the host receiving connections), while the usermsg is meant
796 * for a remote user who may or may not be clueful, and may or may not be
797 * doing something nefarious. Some remote users (eg, MS-Windows...) may not
798 * even see whatever message is sent, which is why there's the option to
799 * start 'lpd' with the connection-errors also sent to syslog.
800 *
801 * Given that hostnames can theoretically be fairly long (well, over 250
802 * bytes), it would probably be helpful to have the 'from_host' field at
803 * the end of any error messages which include that info.
804 *
805 * These are Fatal host-connection errors, so this routine does not return.
806 */
807 static void
fhosterr(int ch_opts,char * sysmsg,char * usermsg)808 fhosterr(int ch_opts, char *sysmsg, char *usermsg)
809 {
810
811 /*
812 * If lpd was started up to print connection errors, then write
813 * the syslog message before the user message.
814 * And for many of the syslog messages, it is helpful to first
815 * write the from_host (if it is known) as a separate syslog
816 * message, since the hostname may be so long.
817 */
818 if (ch_opts & LPD_LOGCONNERR) {
819 if (ch_opts & LPD_ADDFROMLINE) {
820 syslog(LOG_WARNING, "for connection from %s:", from_host);
821 }
822 syslog(LOG_WARNING, "%s", sysmsg);
823 }
824
825 /*
826 * Now send the error message to the remote host which is trying
827 * to make the connection.
828 */
829 printf("%s [@%s]: %s\n", progname, local_host, usermsg);
830 fflush(stdout);
831
832 /*
833 * Add a minimal delay before exiting (and disconnecting from the
834 * sending-host). This is just in case that machine responds by
835 * INSTANTLY retrying (and instantly re-failing...). This may also
836 * give the other side more time to read the error message.
837 */
838 sleep(2); /* a paranoid throttling measure */
839 exit(1);
840 }
841
842 /* setup server socket for specified address family */
843 /* if af is PF_UNSPEC more than one socket may be returned */
844 /* the returned list is dynamically allocated, so caller needs to free it */
845 static int *
socksetup(int af,int debuglvl)846 socksetup(int af, int debuglvl)
847 {
848 struct addrinfo hints, *res, *r;
849 int error, maxs, *s, *socks;
850 const int on = 1;
851
852 memset(&hints, 0, sizeof(hints));
853 hints.ai_flags = AI_PASSIVE;
854 hints.ai_family = af;
855 hints.ai_socktype = SOCK_STREAM;
856 error = getaddrinfo(NULL, "printer", &hints, &res);
857 if (error) {
858 syslog(LOG_ERR, "%s", gai_strerror(error));
859 mcleanup(0);
860 }
861
862 /* Count max number of sockets we may open */
863 for (maxs = 0, r = res; r; r = r->ai_next, maxs++)
864 ;
865 socks = malloc((maxs + 1) * sizeof(int));
866 if (!socks) {
867 syslog(LOG_ERR, "couldn't allocate memory for sockets");
868 mcleanup(0);
869 }
870
871 *socks = 0; /* num of sockets counter at start of array */
872 s = socks + 1;
873 for (r = res; r; r = r->ai_next) {
874 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
875 if (*s < 0) {
876 syslog(LOG_DEBUG, "socket(): %m");
877 continue;
878 }
879 if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))
880 < 0) {
881 syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m");
882 close(*s);
883 continue;
884 }
885 if (debuglvl)
886 if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, &debuglvl,
887 sizeof(debuglvl)) < 0) {
888 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
889 close(*s);
890 continue;
891 }
892 #ifdef IPV6_BINDV6ONLY
893 if (r->ai_family == AF_INET6) {
894 if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY,
895 &on, sizeof(on)) < 0) {
896 syslog(LOG_ERR,
897 "setsockopt (IPV6_BINDV6ONLY): %m");
898 close(*s);
899 continue;
900 }
901 }
902 #endif
903 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
904 syslog(LOG_DEBUG, "bind(): %m");
905 close(*s);
906 continue;
907 }
908 (*socks)++;
909 s++;
910 }
911
912 if (res)
913 freeaddrinfo(res);
914
915 if (*socks == 0) {
916 syslog(LOG_ERR, "Couldn't bind to any socket");
917 free(socks);
918 mcleanup(0);
919 }
920 return(socks);
921 }
922
923 static void
usage(void)924 usage(void)
925 {
926 #ifdef INET6
927 fprintf(stderr, "usage: lpd [-cdlsW46] [port#]\n");
928 #else
929 fprintf(stderr, "usage: lpd [-cdlsW] [port#]\n");
930 #endif
931 exit(EX_USAGE);
932 }
933