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