10b561052SJoerg Wunsch /* 20b561052SJoerg Wunsch * Copyright (c) 1983, 1993, 1994 30b561052SJoerg Wunsch * The Regents of the University of California. All rights reserved. 40b561052SJoerg Wunsch * 50b561052SJoerg Wunsch * 60b561052SJoerg Wunsch * Redistribution and use in source and binary forms, with or without 70b561052SJoerg Wunsch * modification, are permitted provided that the following conditions 80b561052SJoerg Wunsch * are met: 90b561052SJoerg Wunsch * 1. Redistributions of source code must retain the above copyright 100b561052SJoerg Wunsch * notice, this list of conditions and the following disclaimer. 110b561052SJoerg Wunsch * 2. Redistributions in binary form must reproduce the above copyright 120b561052SJoerg Wunsch * notice, this list of conditions and the following disclaimer in the 130b561052SJoerg Wunsch * documentation and/or other materials provided with the distribution. 140b561052SJoerg Wunsch * 3. All advertising materials mentioning features or use of this software 150b561052SJoerg Wunsch * must display the following acknowledgement: 160b561052SJoerg Wunsch * This product includes software developed by the University of 170b561052SJoerg Wunsch * California, Berkeley and its contributors. 180b561052SJoerg Wunsch * 4. Neither the name of the University nor the names of its contributors 190b561052SJoerg Wunsch * may be used to endorse or promote products derived from this software 200b561052SJoerg Wunsch * without specific prior written permission. 210b561052SJoerg Wunsch * 220b561052SJoerg Wunsch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 230b561052SJoerg Wunsch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 240b561052SJoerg Wunsch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 250b561052SJoerg Wunsch * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 260b561052SJoerg Wunsch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 270b561052SJoerg Wunsch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 280b561052SJoerg Wunsch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 290b561052SJoerg Wunsch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 300b561052SJoerg Wunsch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 310b561052SJoerg Wunsch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 320b561052SJoerg Wunsch * SUCH DAMAGE. 330b561052SJoerg Wunsch */ 340b561052SJoerg Wunsch 350b561052SJoerg Wunsch #ifndef lint 369b3fe531SPhilippe Charnier static const char copyright[] = 370b561052SJoerg Wunsch "@(#) Copyright (c) 1983, 1993, 1994\n\ 380b561052SJoerg Wunsch The Regents of the University of California. All rights reserved.\n"; 390b561052SJoerg Wunsch #endif /* not lint */ 400b561052SJoerg Wunsch 410b561052SJoerg Wunsch #ifndef lint 429b3fe531SPhilippe Charnier #if 0 430b561052SJoerg Wunsch static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; 449b3fe531SPhilippe Charnier #endif 459b3fe531SPhilippe Charnier static const char rcsid[] = 4697d92980SPeter Wemm "$FreeBSD$"; 470b561052SJoerg Wunsch #endif /* not lint */ 480b561052SJoerg Wunsch 490b561052SJoerg Wunsch /* 500b561052SJoerg Wunsch * lpd -- line printer daemon. 510b561052SJoerg Wunsch * 520b561052SJoerg Wunsch * Listen for a connection and perform the requested operation. 530b561052SJoerg Wunsch * Operations are: 540b561052SJoerg Wunsch * \1printer\n 550b561052SJoerg Wunsch * check the queue for jobs and print any found. 560b561052SJoerg Wunsch * \2printer\n 570b561052SJoerg Wunsch * receive a job from another machine and queue it. 580b561052SJoerg Wunsch * \3printer [users ...] [jobs ...]\n 590b561052SJoerg Wunsch * return the current state of the queue (short form). 600b561052SJoerg Wunsch * \4printer [users ...] [jobs ...]\n 610b561052SJoerg Wunsch * return the current state of the queue (long form). 620b561052SJoerg Wunsch * \5printer person [users ...] [jobs ...]\n 630b561052SJoerg Wunsch * remove jobs from the queue. 640b561052SJoerg Wunsch * 650b561052SJoerg Wunsch * Strategy to maintain protected spooling area: 660b561052SJoerg Wunsch * 1. Spooling area is writable only by daemon and spooling group 670b561052SJoerg Wunsch * 2. lpr runs setuid root and setgrp spooling group; it uses 680b561052SJoerg Wunsch * root to access any file it wants (verifying things before 690b561052SJoerg Wunsch * with an access call) and group id to know how it should 700b561052SJoerg Wunsch * set up ownership of files in the spooling area. 710b561052SJoerg Wunsch * 3. Files in spooling area are owned by root, group spooling 720b561052SJoerg Wunsch * group, with mode 660. 730b561052SJoerg Wunsch * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to 740b561052SJoerg Wunsch * access files and printer. Users can't get to anything 750b561052SJoerg Wunsch * w/o help of lpq and lprm programs. 760b561052SJoerg Wunsch */ 770b561052SJoerg Wunsch 780b561052SJoerg Wunsch #include <sys/param.h> 790b561052SJoerg Wunsch #include <sys/wait.h> 800b561052SJoerg Wunsch #include <sys/types.h> 810b561052SJoerg Wunsch #include <sys/socket.h> 820b561052SJoerg Wunsch #include <sys/un.h> 830b561052SJoerg Wunsch #include <sys/stat.h> 840b561052SJoerg Wunsch #include <sys/file.h> 850b561052SJoerg Wunsch #include <netinet/in.h> 867f72cbbaSJoerg Wunsch #include <arpa/inet.h> 870b561052SJoerg Wunsch 880b561052SJoerg Wunsch #include <netdb.h> 890b561052SJoerg Wunsch #include <unistd.h> 900b561052SJoerg Wunsch #include <syslog.h> 910b561052SJoerg Wunsch #include <signal.h> 9236d0e2a3SJoerg Wunsch #include <err.h> 930b561052SJoerg Wunsch #include <errno.h> 940b561052SJoerg Wunsch #include <fcntl.h> 950b561052SJoerg Wunsch #include <dirent.h> 960b561052SJoerg Wunsch #include <stdio.h> 970b561052SJoerg Wunsch #include <stdlib.h> 980b561052SJoerg Wunsch #include <string.h> 9936d0e2a3SJoerg Wunsch #include <sysexits.h> 1000b561052SJoerg Wunsch #include <ctype.h> 1010b561052SJoerg Wunsch #include "lp.h" 1020b561052SJoerg Wunsch #include "lp.local.h" 1030b561052SJoerg Wunsch #include "pathnames.h" 1040b561052SJoerg Wunsch #include "extern.h" 1050b561052SJoerg Wunsch 1060b561052SJoerg Wunsch int lflag; /* log requests flag */ 107ba901a11SSheldon Hearn int pflag; /* no incoming port flag */ 1080b561052SJoerg Wunsch int from_remote; /* from remote socket */ 1090b561052SJoerg Wunsch 110ba7a1ad7SGarance A Drosehn int main(int argc, char **_argv); 111ba7a1ad7SGarance A Drosehn static void reapchild(int _signo); 112ba7a1ad7SGarance A Drosehn static void mcleanup(int _signo); 113ba7a1ad7SGarance A Drosehn static void doit(void); 114ba7a1ad7SGarance A Drosehn static void startup(void); 1156ddb63caSGarance A Drosehn static void chkhost(struct sockaddr *_f, int _ch_opts); 116ba7a1ad7SGarance A Drosehn static int ckqueue(struct printer *_pp); 1176ddb63caSGarance A Drosehn static void fhosterr(int _dosys, const char *_sysmsg, const char *_usermsg, 1186ddb63caSGarance A Drosehn ...); 119aa4ad562SGarance A Drosehn static int *socksetup(int _af, int _debuglvl); 120ba7a1ad7SGarance A Drosehn static void usage(void); 12108829865SHajimu UMEMOTO 12208829865SHajimu UMEMOTO /* XXX from libc/net/rcmd.c */ 12308829865SHajimu UMEMOTO extern int __ivaliduser_sa __P((FILE *, struct sockaddr *, socklen_t, 12408829865SHajimu UMEMOTO const char *, const char *)); 1250b561052SJoerg Wunsch 126360d4ad5SWarner Losh uid_t uid, euid; 127360d4ad5SWarner Losh 1286ddb63caSGarance A Drosehn #define LPD_NOPORTCHK 0001 /* skip reserved-port check */ 1296ddb63caSGarance A Drosehn #define LPD_LOGCONNERR 0002 /* (sys)log connection errors */ 1306ddb63caSGarance A Drosehn 1310b561052SJoerg Wunsch int 132ba7a1ad7SGarance A Drosehn main(int argc, char **argv) 1330b561052SJoerg Wunsch { 1346ddb63caSGarance A Drosehn int ch_options, errs, f, funix, *finet, fromlen, i, socket_debug; 1350b561052SJoerg Wunsch fd_set defreadfds; 1360b561052SJoerg Wunsch struct sockaddr_un un, fromunix; 13708829865SHajimu UMEMOTO struct sockaddr_storage frominet; 1384a1a0dbeSGarrett Wollman int lfd; 1394a1a0dbeSGarrett Wollman sigset_t omask, nmask; 14036d0e2a3SJoerg Wunsch struct servent *sp, serv; 14108829865SHajimu UMEMOTO int inet_flag = 0, inet6_flag = 0; 1420b561052SJoerg Wunsch 143360d4ad5SWarner Losh euid = geteuid(); /* these shouldn't be different */ 144360d4ad5SWarner Losh uid = getuid(); 1456ddb63caSGarance A Drosehn 1466ddb63caSGarance A Drosehn ch_options = 0; 147f6a3be39SGarance A Drosehn socket_debug = 0; 148cc3fd56fSGarance A Drosehn gethostname(local_host, sizeof(local_host)); 149360d4ad5SWarner Losh 15031058a75SGarance A Drosehn progname = "lpd"; 151360d4ad5SWarner Losh 15236d0e2a3SJoerg Wunsch if (euid != 0) 15336d0e2a3SJoerg Wunsch errx(EX_NOPERM,"must run as root"); 1540b561052SJoerg Wunsch 15536d0e2a3SJoerg Wunsch errs = 0; 1566ddb63caSGarance A Drosehn while ((i = getopt(argc, argv, "cdlpw46")) != -1) 15736d0e2a3SJoerg Wunsch switch (i) { 1586ddb63caSGarance A Drosehn case 'c': 1596ddb63caSGarance A Drosehn /* log all kinds of connection-errors to syslog */ 1606ddb63caSGarance A Drosehn ch_options |= LPD_LOGCONNERR; 1616ddb63caSGarance A Drosehn break; 1620b561052SJoerg Wunsch case 'd': 163f6a3be39SGarance A Drosehn socket_debug++; 1640b561052SJoerg Wunsch break; 1650b561052SJoerg Wunsch case 'l': 1660b561052SJoerg Wunsch lflag++; 1670b561052SJoerg Wunsch break; 168ba901a11SSheldon Hearn case 'p': 169ba901a11SSheldon Hearn pflag++; 170ba901a11SSheldon Hearn break; 1716ddb63caSGarance A Drosehn case 'w': 1726ddb63caSGarance A Drosehn /* allow connections coming from a non-reserved port */ 1736ddb63caSGarance A Drosehn /* (done by some lpr-implementations for MS-Windows) */ 1746ddb63caSGarance A Drosehn ch_options |= LPD_NOPORTCHK; 1756ddb63caSGarance A Drosehn break; 17608829865SHajimu UMEMOTO case '4': 17708829865SHajimu UMEMOTO family = PF_INET; 17808829865SHajimu UMEMOTO inet_flag++; 17908829865SHajimu UMEMOTO break; 18008829865SHajimu UMEMOTO case '6': 181affa0039SGarance A Drosehn #ifdef INET6 18208829865SHajimu UMEMOTO family = PF_INET6; 18308829865SHajimu UMEMOTO inet6_flag++; 184affa0039SGarance A Drosehn #else 185affa0039SGarance A Drosehn errx(EX_USAGE, "lpd compiled sans INET6 (IPv6 support)"); 186affa0039SGarance A Drosehn #endif 18708829865SHajimu UMEMOTO break; 18836d0e2a3SJoerg Wunsch default: 18936d0e2a3SJoerg Wunsch errs++; 1900b561052SJoerg Wunsch } 19108829865SHajimu UMEMOTO if (inet_flag && inet6_flag) 19208829865SHajimu UMEMOTO family = PF_UNSPEC; 19336d0e2a3SJoerg Wunsch argc -= optind; 19436d0e2a3SJoerg Wunsch argv += optind; 19536d0e2a3SJoerg Wunsch if (errs) 19636d0e2a3SJoerg Wunsch usage(); 19736d0e2a3SJoerg Wunsch 19836d0e2a3SJoerg Wunsch if (argc == 1) { 19936d0e2a3SJoerg Wunsch if ((i = atoi(argv[0])) == 0) 20036d0e2a3SJoerg Wunsch usage(); 20136d0e2a3SJoerg Wunsch if (i < 0 || i > USHRT_MAX) 20236d0e2a3SJoerg Wunsch errx(EX_USAGE, "port # %d is invalid", i); 20336d0e2a3SJoerg Wunsch 20436d0e2a3SJoerg Wunsch serv.s_port = htons(i); 20536d0e2a3SJoerg Wunsch sp = &serv; 20636d0e2a3SJoerg Wunsch argc--; 20736d0e2a3SJoerg Wunsch } else { 20836d0e2a3SJoerg Wunsch sp = getservbyname("printer", "tcp"); 20936d0e2a3SJoerg Wunsch if (sp == NULL) 21036d0e2a3SJoerg Wunsch errx(EX_OSFILE, "printer/tcp: unknown service"); 2110b561052SJoerg Wunsch } 2120b561052SJoerg Wunsch 21336d0e2a3SJoerg Wunsch if (argc != 0) 21436d0e2a3SJoerg Wunsch usage(); 21536d0e2a3SJoerg Wunsch 2164a1a0dbeSGarrett Wollman /* 2174a1a0dbeSGarrett Wollman * We run chkprintcap right away to catch any errors and blat them 2184a1a0dbeSGarrett Wollman * to stderr while we still have it open, rather than sending them 2194a1a0dbeSGarrett Wollman * to syslog and leaving the user wondering why lpd started and 2204a1a0dbeSGarrett Wollman * then stopped. There should probably be a command-line flag to 2214a1a0dbeSGarrett Wollman * ignore errors from chkprintcap. 2224a1a0dbeSGarrett Wollman */ 2234a1a0dbeSGarrett Wollman { 2244a1a0dbeSGarrett Wollman pid_t pid; 2254a1a0dbeSGarrett Wollman int status; 2264a1a0dbeSGarrett Wollman pid = fork(); 2274a1a0dbeSGarrett Wollman if (pid < 0) { 2284a1a0dbeSGarrett Wollman err(EX_OSERR, "cannot fork"); 2294a1a0dbeSGarrett Wollman } else if (pid == 0) { /* child */ 2304a1a0dbeSGarrett Wollman execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); 2314a1a0dbeSGarrett Wollman err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); 2324a1a0dbeSGarrett Wollman } 2334a1a0dbeSGarrett Wollman if (waitpid(pid, &status, 0) < 0) { 2344a1a0dbeSGarrett Wollman err(EX_OSERR, "cannot wait"); 2354a1a0dbeSGarrett Wollman } 2364a1a0dbeSGarrett Wollman if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 2374a1a0dbeSGarrett Wollman errx(EX_OSFILE, "%d errors in printcap file, exiting", 2384a1a0dbeSGarrett Wollman WEXITSTATUS(status)); 2394a1a0dbeSGarrett Wollman } 2404a1a0dbeSGarrett Wollman 2410b561052SJoerg Wunsch #ifndef DEBUG 2420b561052SJoerg Wunsch /* 2430b561052SJoerg Wunsch * Set up standard environment by detaching from the parent. 2440b561052SJoerg Wunsch */ 2450b561052SJoerg Wunsch daemon(0, 0); 2460b561052SJoerg Wunsch #endif 2470b561052SJoerg Wunsch 2480b561052SJoerg Wunsch openlog("lpd", LOG_PID, LOG_LPR); 249f6a3be39SGarance A Drosehn syslog(LOG_INFO, "lpd startup: logging=%d%s", lflag, 250f6a3be39SGarance A Drosehn socket_debug ? " dbg" : ""); 2510b561052SJoerg Wunsch (void) umask(0); 2524a1a0dbeSGarrett Wollman /* 2534a1a0dbeSGarrett Wollman * NB: This depends on O_NONBLOCK semantics doing the right thing; 2544a1a0dbeSGarrett Wollman * i.e., applying only to the O_EXLOCK and not to the rest of the 2554a1a0dbeSGarrett Wollman * open/creation. As of 1997-12-02, this is the case for commonly- 2564a1a0dbeSGarrett Wollman * used filesystems. There are other places in this code which 2574a1a0dbeSGarrett Wollman * make the same assumption. 2584a1a0dbeSGarrett Wollman */ 2594a1a0dbeSGarrett Wollman lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 2604a1a0dbeSGarrett Wollman LOCK_FILE_MODE); 2610b561052SJoerg Wunsch if (lfd < 0) { 2620b561052SJoerg Wunsch if (errno == EWOULDBLOCK) /* active deamon present */ 2630b561052SJoerg Wunsch exit(0); 2640b561052SJoerg Wunsch syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 2650b561052SJoerg Wunsch exit(1); 2660b561052SJoerg Wunsch } 2674a1a0dbeSGarrett Wollman fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ 2680b561052SJoerg Wunsch ftruncate(lfd, 0); 2690b561052SJoerg Wunsch /* 2700b561052SJoerg Wunsch * write process id for others to know 2710b561052SJoerg Wunsch */ 2720b561052SJoerg Wunsch sprintf(line, "%u\n", getpid()); 2730b561052SJoerg Wunsch f = strlen(line); 2740b561052SJoerg Wunsch if (write(lfd, line, f) != f) { 2750b561052SJoerg Wunsch syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 2760b561052SJoerg Wunsch exit(1); 2770b561052SJoerg Wunsch } 2780b561052SJoerg Wunsch signal(SIGCHLD, reapchild); 2790b561052SJoerg Wunsch /* 2800b561052SJoerg Wunsch * Restart all the printers. 2810b561052SJoerg Wunsch */ 2820b561052SJoerg Wunsch startup(); 2830b561052SJoerg Wunsch (void) unlink(_PATH_SOCKETNAME); 2840b561052SJoerg Wunsch funix = socket(AF_UNIX, SOCK_STREAM, 0); 2850b561052SJoerg Wunsch if (funix < 0) { 2860b561052SJoerg Wunsch syslog(LOG_ERR, "socket: %m"); 2870b561052SJoerg Wunsch exit(1); 2880b561052SJoerg Wunsch } 2894a1a0dbeSGarrett Wollman 2904a1a0dbeSGarrett Wollman sigemptyset(&nmask); 2914a1a0dbeSGarrett Wollman sigaddset(&nmask, SIGHUP); 2924a1a0dbeSGarrett Wollman sigaddset(&nmask, SIGINT); 2934a1a0dbeSGarrett Wollman sigaddset(&nmask, SIGQUIT); 2944a1a0dbeSGarrett Wollman sigaddset(&nmask, SIGTERM); 2954a1a0dbeSGarrett Wollman sigprocmask(SIG_BLOCK, &nmask, &omask); 2964a1a0dbeSGarrett Wollman 297bc407914SWarner Losh (void) umask(07); 2980b561052SJoerg Wunsch signal(SIGHUP, mcleanup); 2990b561052SJoerg Wunsch signal(SIGINT, mcleanup); 3000b561052SJoerg Wunsch signal(SIGQUIT, mcleanup); 3010b561052SJoerg Wunsch signal(SIGTERM, mcleanup); 3020b561052SJoerg Wunsch memset(&un, 0, sizeof(un)); 3030b561052SJoerg Wunsch un.sun_family = AF_UNIX; 3040b561052SJoerg Wunsch strcpy(un.sun_path, _PATH_SOCKETNAME); 3050b561052SJoerg Wunsch #ifndef SUN_LEN 3060b561052SJoerg Wunsch #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 3070b561052SJoerg Wunsch #endif 3080b561052SJoerg Wunsch if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 3090b561052SJoerg Wunsch syslog(LOG_ERR, "ubind: %m"); 3100b561052SJoerg Wunsch exit(1); 3110b561052SJoerg Wunsch } 312bc407914SWarner Losh (void) umask(0); 3134a1a0dbeSGarrett Wollman sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 3140b561052SJoerg Wunsch FD_ZERO(&defreadfds); 3150b561052SJoerg Wunsch FD_SET(funix, &defreadfds); 3160b561052SJoerg Wunsch listen(funix, 5); 317ba901a11SSheldon Hearn if (pflag == 0) { 318aa4ad562SGarance A Drosehn finet = socksetup(family, socket_debug); 31908829865SHajimu UMEMOTO } else 32008829865SHajimu UMEMOTO finet = NULL; /* pretend we couldn't open TCP socket. */ 32108829865SHajimu UMEMOTO if (finet) { 32208829865SHajimu UMEMOTO for (i = 1; i <= *finet; i++) { 32308829865SHajimu UMEMOTO FD_SET(finet[i], &defreadfds); 32408829865SHajimu UMEMOTO listen(finet[i], 5); 3250b561052SJoerg Wunsch } 326ba901a11SSheldon Hearn } 3270b561052SJoerg Wunsch /* 3280b561052SJoerg Wunsch * Main loop: accept, do a request, continue. 3290b561052SJoerg Wunsch */ 3300b561052SJoerg Wunsch memset(&frominet, 0, sizeof(frominet)); 3310b561052SJoerg Wunsch memset(&fromunix, 0, sizeof(fromunix)); 332f6a3be39SGarance A Drosehn if (lflag) 333f6a3be39SGarance A Drosehn syslog(LOG_INFO, "lpd startup: ready to accept requests"); 3344a1a0dbeSGarrett Wollman /* 3354a1a0dbeSGarrett Wollman * XXX - should be redone for multi-protocol 3364a1a0dbeSGarrett Wollman */ 3370b561052SJoerg Wunsch for (;;) { 338aa4ad562SGarance A Drosehn int domain, nfds, s; 3390b561052SJoerg Wunsch fd_set readfds; 3400b561052SJoerg Wunsch 3410b561052SJoerg Wunsch FD_COPY(&defreadfds, &readfds); 3420b561052SJoerg Wunsch nfds = select(20, &readfds, 0, 0, 0); 3430b561052SJoerg Wunsch if (nfds <= 0) { 3440b561052SJoerg Wunsch if (nfds < 0 && errno != EINTR) 3450b561052SJoerg Wunsch syslog(LOG_WARNING, "select: %m"); 3460b561052SJoerg Wunsch continue; 3470b561052SJoerg Wunsch } 348aa4ad562SGarance A Drosehn domain = -1; /* avoid compile-time warning */ 349aa4ad562SGarance A Drosehn s = -1; /* avoid compile-time warning */ 3500b561052SJoerg Wunsch if (FD_ISSET(funix, &readfds)) { 3510b561052SJoerg Wunsch domain = AF_UNIX, fromlen = sizeof(fromunix); 3520b561052SJoerg Wunsch s = accept(funix, 3530b561052SJoerg Wunsch (struct sockaddr *)&fromunix, &fromlen); 35408829865SHajimu UMEMOTO } else { 35508829865SHajimu UMEMOTO for (i = 1; i <= *finet; i++) 35608829865SHajimu UMEMOTO if (FD_ISSET(finet[i], &readfds)) { 35708829865SHajimu UMEMOTO domain = AF_INET; 35808829865SHajimu UMEMOTO fromlen = sizeof(frominet); 35908829865SHajimu UMEMOTO s = accept(finet[i], 36008829865SHajimu UMEMOTO (struct sockaddr *)&frominet, 36108829865SHajimu UMEMOTO &fromlen); 362bc407914SWarner Losh } 3630b561052SJoerg Wunsch } 3640b561052SJoerg Wunsch if (s < 0) { 3650b561052SJoerg Wunsch if (errno != EINTR) 3660b561052SJoerg Wunsch syslog(LOG_WARNING, "accept: %m"); 3670b561052SJoerg Wunsch continue; 3680b561052SJoerg Wunsch } 3690b561052SJoerg Wunsch if (fork() == 0) { 370bfb9fa63SGarance A Drosehn /* 371bfb9fa63SGarance A Drosehn * Note that printjob() also plays around with 372bfb9fa63SGarance A Drosehn * signal-handling routines, and may need to be 373bfb9fa63SGarance A Drosehn * changed when making changes to signal-handling. 374bfb9fa63SGarance A Drosehn */ 375bfb9fa63SGarance A Drosehn signal(SIGCHLD, SIG_DFL); 3760b561052SJoerg Wunsch signal(SIGHUP, SIG_IGN); 3770b561052SJoerg Wunsch signal(SIGINT, SIG_IGN); 3780b561052SJoerg Wunsch signal(SIGQUIT, SIG_IGN); 3790b561052SJoerg Wunsch signal(SIGTERM, SIG_IGN); 3800b561052SJoerg Wunsch (void) close(funix); 38108829865SHajimu UMEMOTO if (pflag == 0 && finet) { 38208829865SHajimu UMEMOTO for (i = 1; i <= *finet; i++) 38308829865SHajimu UMEMOTO (void)close(finet[i]); 384ba901a11SSheldon Hearn } 3850b561052SJoerg Wunsch dup2(s, 1); 3860b561052SJoerg Wunsch (void) close(s); 3870b561052SJoerg Wunsch if (domain == AF_INET) { 38808829865SHajimu UMEMOTO /* for both AF_INET and AF_INET6 */ 3890b561052SJoerg Wunsch from_remote = 1; 3906ddb63caSGarance A Drosehn chkhost((struct sockaddr *)&frominet, 3916ddb63caSGarance A Drosehn ch_options); 3920b561052SJoerg Wunsch } else 3930b561052SJoerg Wunsch from_remote = 0; 3940b561052SJoerg Wunsch doit(); 3950b561052SJoerg Wunsch exit(0); 3960b561052SJoerg Wunsch } 3970b561052SJoerg Wunsch (void) close(s); 3980b561052SJoerg Wunsch } 3990b561052SJoerg Wunsch } 4000b561052SJoerg Wunsch 4010b561052SJoerg Wunsch static void 402ba7a1ad7SGarance A Drosehn reapchild(int signo __unused) 4030b561052SJoerg Wunsch { 4040b561052SJoerg Wunsch union wait status; 4050b561052SJoerg Wunsch 4060b561052SJoerg Wunsch while (wait3((int *)&status, WNOHANG, 0) > 0) 4070b561052SJoerg Wunsch ; 4080b561052SJoerg Wunsch } 4090b561052SJoerg Wunsch 4100b561052SJoerg Wunsch static void 411ba7a1ad7SGarance A Drosehn mcleanup(int signo) 4120b561052SJoerg Wunsch { 413545ed065SGarrett Wollman /* 414545ed065SGarrett Wollman * XXX syslog(3) is not signal-safe. 415545ed065SGarrett Wollman */ 416545ed065SGarrett Wollman if (lflag) { 417545ed065SGarrett Wollman if (signo) 418545ed065SGarrett Wollman syslog(LOG_INFO, "exiting on signal %d", signo); 419545ed065SGarrett Wollman else 4200b561052SJoerg Wunsch syslog(LOG_INFO, "exiting"); 421545ed065SGarrett Wollman } 4220b561052SJoerg Wunsch unlink(_PATH_SOCKETNAME); 4230b561052SJoerg Wunsch exit(0); 4240b561052SJoerg Wunsch } 4250b561052SJoerg Wunsch 4260b561052SJoerg Wunsch /* 4270b561052SJoerg Wunsch * Stuff for handling job specifications 4280b561052SJoerg Wunsch */ 4290b561052SJoerg Wunsch char *user[MAXUSERS]; /* users to process */ 4300b561052SJoerg Wunsch int users; /* # of users in user array */ 4310b561052SJoerg Wunsch int requ[MAXREQUESTS]; /* job number of spool entries */ 4320b561052SJoerg Wunsch int requests; /* # of spool requests */ 4330b561052SJoerg Wunsch char *person; /* name of person doing lprm */ 4340b561052SJoerg Wunsch 435cc3fd56fSGarance A Drosehn /* buffer to hold the client's machine-name */ 436cc3fd56fSGarance A Drosehn static char frombuf[MAXHOSTNAMELEN]; 4370b561052SJoerg Wunsch char cbuf[BUFSIZ]; /* command line buffer */ 438ba7a1ad7SGarance A Drosehn const char *cmdnames[] = { 4390b561052SJoerg Wunsch "null", 4400b561052SJoerg Wunsch "printjob", 4410b561052SJoerg Wunsch "recvjob", 4420b561052SJoerg Wunsch "displayq short", 4430b561052SJoerg Wunsch "displayq long", 4440b561052SJoerg Wunsch "rmjob" 4450b561052SJoerg Wunsch }; 4460b561052SJoerg Wunsch 4470b561052SJoerg Wunsch static void 448ba7a1ad7SGarance A Drosehn doit(void) 4490b561052SJoerg Wunsch { 4504a1a0dbeSGarrett Wollman char *cp, *printer; 4514a1a0dbeSGarrett Wollman int n; 4524a1a0dbeSGarrett Wollman int status; 4534a1a0dbeSGarrett Wollman struct printer myprinter, *pp = &myprinter; 4544a1a0dbeSGarrett Wollman 4554a1a0dbeSGarrett Wollman init_printer(&myprinter); 4560b561052SJoerg Wunsch 4570b561052SJoerg Wunsch for (;;) { 4580b561052SJoerg Wunsch cp = cbuf; 4590b561052SJoerg Wunsch do { 4600b561052SJoerg Wunsch if (cp >= &cbuf[sizeof(cbuf) - 1]) 4614a1a0dbeSGarrett Wollman fatal(0, "Command line too long"); 4620b561052SJoerg Wunsch if ((n = read(1, cp, 1)) != 1) { 4630b561052SJoerg Wunsch if (n < 0) 4644a1a0dbeSGarrett Wollman fatal(0, "Lost connection"); 4650b561052SJoerg Wunsch return; 4660b561052SJoerg Wunsch } 4670b561052SJoerg Wunsch } while (*cp++ != '\n'); 4680b561052SJoerg Wunsch *--cp = '\0'; 4690b561052SJoerg Wunsch cp = cbuf; 4700b561052SJoerg Wunsch if (lflag) { 4710b561052SJoerg Wunsch if (*cp >= '\1' && *cp <= '\5') 4720b561052SJoerg Wunsch syslog(LOG_INFO, "%s requests %s %s", 473cc3fd56fSGarance A Drosehn from_host, cmdnames[(u_char)*cp], cp+1); 4740b561052SJoerg Wunsch else 4750b561052SJoerg Wunsch syslog(LOG_INFO, "bad request (%d) from %s", 476cc3fd56fSGarance A Drosehn *cp, from_host); 4770b561052SJoerg Wunsch } 4780b561052SJoerg Wunsch switch (*cp++) { 4794a1a0dbeSGarrett Wollman case CMD_CHECK_QUE: /* check the queue, print any jobs there */ 4804a1a0dbeSGarrett Wollman startprinting(cp); 4810b561052SJoerg Wunsch break; 4824a1a0dbeSGarrett Wollman case CMD_TAKE_THIS: /* receive files to be queued */ 4830b561052SJoerg Wunsch if (!from_remote) { 4840b561052SJoerg Wunsch syslog(LOG_INFO, "illegal request (%d)", *cp); 4850b561052SJoerg Wunsch exit(1); 4860b561052SJoerg Wunsch } 4874a1a0dbeSGarrett Wollman recvjob(cp); 4880b561052SJoerg Wunsch break; 4894a1a0dbeSGarrett Wollman case CMD_SHOWQ_SHORT: /* display the queue (short form) */ 4904a1a0dbeSGarrett Wollman case CMD_SHOWQ_LONG: /* display the queue (long form) */ 4914a1a0dbeSGarrett Wollman /* XXX - this all needs to be redone. */ 4920b561052SJoerg Wunsch printer = cp; 4930b561052SJoerg Wunsch while (*cp) { 4940b561052SJoerg Wunsch if (*cp != ' ') { 4950b561052SJoerg Wunsch cp++; 4960b561052SJoerg Wunsch continue; 4970b561052SJoerg Wunsch } 4980b561052SJoerg Wunsch *cp++ = '\0'; 4990b561052SJoerg Wunsch while (isspace(*cp)) 5000b561052SJoerg Wunsch cp++; 5010b561052SJoerg Wunsch if (*cp == '\0') 5020b561052SJoerg Wunsch break; 5030b561052SJoerg Wunsch if (isdigit(*cp)) { 5040b561052SJoerg Wunsch if (requests >= MAXREQUESTS) 5054a1a0dbeSGarrett Wollman fatal(0, "Too many requests"); 5060b561052SJoerg Wunsch requ[requests++] = atoi(cp); 5070b561052SJoerg Wunsch } else { 5080b561052SJoerg Wunsch if (users >= MAXUSERS) 5094a1a0dbeSGarrett Wollman fatal(0, "Too many users"); 5100b561052SJoerg Wunsch user[users++] = cp; 5110b561052SJoerg Wunsch } 5120b561052SJoerg Wunsch } 5134a1a0dbeSGarrett Wollman status = getprintcap(printer, pp); 5144a1a0dbeSGarrett Wollman if (status < 0) 5154a1a0dbeSGarrett Wollman fatal(pp, pcaperr(status)); 5164a1a0dbeSGarrett Wollman displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); 5170b561052SJoerg Wunsch exit(0); 5184a1a0dbeSGarrett Wollman case CMD_RMJOB: /* remove a job from the queue */ 5190b561052SJoerg Wunsch if (!from_remote) { 5200b561052SJoerg Wunsch syslog(LOG_INFO, "illegal request (%d)", *cp); 5210b561052SJoerg Wunsch exit(1); 5220b561052SJoerg Wunsch } 5230b561052SJoerg Wunsch printer = cp; 5240b561052SJoerg Wunsch while (*cp && *cp != ' ') 5250b561052SJoerg Wunsch cp++; 5260b561052SJoerg Wunsch if (!*cp) 5270b561052SJoerg Wunsch break; 5280b561052SJoerg Wunsch *cp++ = '\0'; 5290b561052SJoerg Wunsch person = cp; 5300b561052SJoerg Wunsch while (*cp) { 5310b561052SJoerg Wunsch if (*cp != ' ') { 5320b561052SJoerg Wunsch cp++; 5330b561052SJoerg Wunsch continue; 5340b561052SJoerg Wunsch } 5350b561052SJoerg Wunsch *cp++ = '\0'; 5360b561052SJoerg Wunsch while (isspace(*cp)) 5370b561052SJoerg Wunsch cp++; 5380b561052SJoerg Wunsch if (*cp == '\0') 5390b561052SJoerg Wunsch break; 5400b561052SJoerg Wunsch if (isdigit(*cp)) { 5410b561052SJoerg Wunsch if (requests >= MAXREQUESTS) 5424a1a0dbeSGarrett Wollman fatal(0, "Too many requests"); 5430b561052SJoerg Wunsch requ[requests++] = atoi(cp); 5440b561052SJoerg Wunsch } else { 5450b561052SJoerg Wunsch if (users >= MAXUSERS) 5464a1a0dbeSGarrett Wollman fatal(0, "Too many users"); 5470b561052SJoerg Wunsch user[users++] = cp; 5480b561052SJoerg Wunsch } 5490b561052SJoerg Wunsch } 5504a1a0dbeSGarrett Wollman rmjob(printer); 5510b561052SJoerg Wunsch break; 5520b561052SJoerg Wunsch } 5534a1a0dbeSGarrett Wollman fatal(0, "Illegal service request"); 5540b561052SJoerg Wunsch } 5550b561052SJoerg Wunsch } 5560b561052SJoerg Wunsch 5570b561052SJoerg Wunsch /* 5580b561052SJoerg Wunsch * Make a pass through the printcap database and start printing any 5590b561052SJoerg Wunsch * files left from the last time the machine went down. 5600b561052SJoerg Wunsch */ 5610b561052SJoerg Wunsch static void 562ba7a1ad7SGarance A Drosehn startup(void) 5630b561052SJoerg Wunsch { 5644a1a0dbeSGarrett Wollman int pid, status, more; 5654a1a0dbeSGarrett Wollman struct printer myprinter, *pp = &myprinter; 5660b561052SJoerg Wunsch 5674a1a0dbeSGarrett Wollman more = firstprinter(pp, &status); 5684a1a0dbeSGarrett Wollman if (status) 5694a1a0dbeSGarrett Wollman goto errloop; 5704a1a0dbeSGarrett Wollman while (more) { 5714a1a0dbeSGarrett Wollman if (ckqueue(pp) <= 0) { 5724a1a0dbeSGarrett Wollman goto next; 5730b561052SJoerg Wunsch } 5740b561052SJoerg Wunsch if (lflag) 575f6a3be39SGarance A Drosehn syslog(LOG_INFO, "lpd startup: work for %s", 576f6a3be39SGarance A Drosehn pp->printer); 5770b561052SJoerg Wunsch if ((pid = fork()) < 0) { 578f6a3be39SGarance A Drosehn syslog(LOG_WARNING, "lpd startup: cannot fork for %s", 579f6a3be39SGarance A Drosehn pp->printer); 5800b561052SJoerg Wunsch mcleanup(0); 5810b561052SJoerg Wunsch } 5824a1a0dbeSGarrett Wollman if (pid == 0) { 5834a1a0dbeSGarrett Wollman lastprinter(); 5844a1a0dbeSGarrett Wollman printjob(pp); 5850b561052SJoerg Wunsch /* NOTREACHED */ 5860b561052SJoerg Wunsch } 5874a1a0dbeSGarrett Wollman do { 5884a1a0dbeSGarrett Wollman next: 5894a1a0dbeSGarrett Wollman more = nextprinter(pp, &status); 5904a1a0dbeSGarrett Wollman errloop: 5914a1a0dbeSGarrett Wollman if (status) 5924a1a0dbeSGarrett Wollman syslog(LOG_WARNING, 593f6a3be39SGarance A Drosehn "lpd startup: printcap entry for %s has errors, skipping", 594685f7a38SGarance A Drosehn pp->printer ? pp->printer : "<noname?>"); 5954a1a0dbeSGarrett Wollman } while (more && status); 5960b561052SJoerg Wunsch } 5970b561052SJoerg Wunsch } 5980b561052SJoerg Wunsch 5990b561052SJoerg Wunsch /* 6000b561052SJoerg Wunsch * Make sure there's some work to do before forking off a child 6010b561052SJoerg Wunsch */ 6020b561052SJoerg Wunsch static int 603ba7a1ad7SGarance A Drosehn ckqueue(struct printer *pp) 6040b561052SJoerg Wunsch { 6050b561052SJoerg Wunsch register struct dirent *d; 6060b561052SJoerg Wunsch DIR *dirp; 6070b561052SJoerg Wunsch char *spooldir; 6080b561052SJoerg Wunsch 6094a1a0dbeSGarrett Wollman spooldir = pp->spool_dir; 6100b561052SJoerg Wunsch if ((dirp = opendir(spooldir)) == NULL) 6110b561052SJoerg Wunsch return (-1); 6120b561052SJoerg Wunsch while ((d = readdir(dirp)) != NULL) { 6130b561052SJoerg Wunsch if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 6140b561052SJoerg Wunsch continue; /* daemon control files only */ 6150b561052SJoerg Wunsch closedir(dirp); 6160b561052SJoerg Wunsch return (1); /* found something */ 6170b561052SJoerg Wunsch } 6180b561052SJoerg Wunsch closedir(dirp); 6190b561052SJoerg Wunsch return (0); 6200b561052SJoerg Wunsch } 6210b561052SJoerg Wunsch 6220b561052SJoerg Wunsch #define DUMMY ":nobody::" 6230b561052SJoerg Wunsch 6240b561052SJoerg Wunsch /* 6256ddb63caSGarance A Drosehn * Check to see if the host connecting to this host has access to any 6266ddb63caSGarance A Drosehn * lpd services on this host. 6270b561052SJoerg Wunsch */ 6280b561052SJoerg Wunsch static void 6296ddb63caSGarance A Drosehn chkhost(struct sockaddr *f, int ch_opts) 6300b561052SJoerg Wunsch { 63108829865SHajimu UMEMOTO struct addrinfo hints, *res, *r; 6320b561052SJoerg Wunsch register FILE *hostf; 633cc3fd56fSGarance A Drosehn char hostbuf[NI_MAXHOST], ip[NI_MAXHOST]; 63408829865SHajimu UMEMOTO char serv[NI_MAXSERV]; 6356ddb63caSGarance A Drosehn int error, errsav, fpass, good, wantsl; 63608829865SHajimu UMEMOTO 6376ddb63caSGarance A Drosehn wantsl = 0; 6386ddb63caSGarance A Drosehn if (ch_opts & LPD_LOGCONNERR) 6396ddb63caSGarance A Drosehn wantsl = 1; /* also syslog the errors */ 6406ddb63caSGarance A Drosehn 6416ddb63caSGarance A Drosehn from_host = ".na."; 6420b561052SJoerg Wunsch 6430b561052SJoerg Wunsch /* Need real hostname for temporary filenames */ 644cc3fd56fSGarance A Drosehn error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, 64508829865SHajimu UMEMOTO NI_NAMEREQD); 64608829865SHajimu UMEMOTO if (error) { 6476ddb63caSGarance A Drosehn errsav = error; 648cc3fd56fSGarance A Drosehn error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), 649cc3fd56fSGarance A Drosehn NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); 65008829865SHajimu UMEMOTO if (error) 6516ddb63caSGarance A Drosehn fhosterr(wantsl, 6526ddb63caSGarance A Drosehn "can not determine hostname for remote host (%d)", 6536ddb63caSGarance A Drosehn "Host name for your address not known", error); 65408829865SHajimu UMEMOTO else 6556ddb63caSGarance A Drosehn fhosterr(wantsl, 6566ddb63caSGarance A Drosehn "Host name for remote host (%s) not known (%d)", 6576ddb63caSGarance A Drosehn "Host name for your address (%s) not known", 6586ddb63caSGarance A Drosehn hostbuf, errsav); 65908829865SHajimu UMEMOTO } 6600b561052SJoerg Wunsch 661cc3fd56fSGarance A Drosehn strlcpy(frombuf, hostbuf, sizeof(frombuf)); 662cc3fd56fSGarance A Drosehn from_host = frombuf; 66308829865SHajimu UMEMOTO 66408829865SHajimu UMEMOTO /* Need address in stringform for comparison (no DNS lookup here) */ 665cc3fd56fSGarance A Drosehn error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, 66608829865SHajimu UMEMOTO NI_NUMERICHOST | NI_WITHSCOPEID); 66708829865SHajimu UMEMOTO if (error) 6686ddb63caSGarance A Drosehn fhosterr(wantsl, "Cannot print IP address (error %d)", 6696ddb63caSGarance A Drosehn "Cannot print IP address", error); 670cc3fd56fSGarance A Drosehn from_ip = strdup(hostbuf); 6710b561052SJoerg Wunsch 67208829865SHajimu UMEMOTO /* Reject numeric addresses */ 67308829865SHajimu UMEMOTO memset(&hints, 0, sizeof(hints)); 67408829865SHajimu UMEMOTO hints.ai_family = family; 67508829865SHajimu UMEMOTO hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 67608829865SHajimu UMEMOTO hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 677cc3fd56fSGarance A Drosehn if (getaddrinfo(from_host, NULL, &hints, &res) == 0) { 67808829865SHajimu UMEMOTO freeaddrinfo(res); 6796ddb63caSGarance A Drosehn fhosterr(wantsl, NULL, "reverse lookup results in non-FQDN %s", 6806ddb63caSGarance A Drosehn from_host); 68108829865SHajimu UMEMOTO } 68208829865SHajimu UMEMOTO 683bc407914SWarner Losh /* Check for spoof, ala rlogind */ 68408829865SHajimu UMEMOTO memset(&hints, 0, sizeof(hints)); 68508829865SHajimu UMEMOTO hints.ai_family = family; 68608829865SHajimu UMEMOTO hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 687cc3fd56fSGarance A Drosehn error = getaddrinfo(from_host, NULL, &hints, &res); 68808829865SHajimu UMEMOTO if (error) { 6896ddb63caSGarance A Drosehn fhosterr(wantsl, "dns lookup for address %s failed: %s", 6906ddb63caSGarance A Drosehn "hostname for your address (%s) unknown: %s", from_ip, 69108829865SHajimu UMEMOTO gai_strerror(error)); 69208829865SHajimu UMEMOTO } 69308829865SHajimu UMEMOTO good = 0; 69408829865SHajimu UMEMOTO for (r = res; good == 0 && r; r = r->ai_next) { 69508829865SHajimu UMEMOTO error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip), 69608829865SHajimu UMEMOTO NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); 69708829865SHajimu UMEMOTO if (!error && !strcmp(from_ip, ip)) 698bc407914SWarner Losh good = 1; 699bc407914SWarner Losh } 70008829865SHajimu UMEMOTO if (res) 70108829865SHajimu UMEMOTO freeaddrinfo(res); 702bc407914SWarner Losh if (good == 0) 7036ddb63caSGarance A Drosehn fhosterr(wantsl, "address for remote host (%s) not matched", 7046ddb63caSGarance A Drosehn "address for your hostname (%s) not matched", from_ip); 705bc407914SWarner Losh 7066ddb63caSGarance A Drosehn fpass = 1; 7070b561052SJoerg Wunsch hostf = fopen(_PATH_HOSTSEQUIV, "r"); 7080b561052SJoerg Wunsch again: 7090b561052SJoerg Wunsch if (hostf) { 71008829865SHajimu UMEMOTO if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 7110b561052SJoerg Wunsch (void) fclose(hostf); 7126ddb63caSGarance A Drosehn goto foundhost; 7130b561052SJoerg Wunsch } 7140b561052SJoerg Wunsch (void) fclose(hostf); 7150b561052SJoerg Wunsch } 7166ddb63caSGarance A Drosehn if (fpass == 1) { 7176ddb63caSGarance A Drosehn fpass = 2; 7180b561052SJoerg Wunsch hostf = fopen(_PATH_HOSTSLPD, "r"); 7190b561052SJoerg Wunsch goto again; 7200b561052SJoerg Wunsch } 7216ddb63caSGarance A Drosehn fhosterr(wantsl, "refused connection from %s, sip=%s", 7226ddb63caSGarance A Drosehn "Print-services are not available to your host (%s).", from_host, 7236ddb63caSGarance A Drosehn from_ip); 7240b561052SJoerg Wunsch /*NOTREACHED*/ 7256ddb63caSGarance A Drosehn 7266ddb63caSGarance A Drosehn foundhost: 7276ddb63caSGarance A Drosehn if (ch_opts & LPD_NOPORTCHK) 7286ddb63caSGarance A Drosehn return; /* skip the reserved-port check */ 7296ddb63caSGarance A Drosehn 7306ddb63caSGarance A Drosehn error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), 7316ddb63caSGarance A Drosehn NI_NUMERICSERV); 7326ddb63caSGarance A Drosehn if (error) 7336ddb63caSGarance A Drosehn fhosterr(wantsl, NULL, "malformed from-address (%d)", error); 7346ddb63caSGarance A Drosehn 7356ddb63caSGarance A Drosehn if (atoi(serv) >= IPPORT_RESERVED) 7366ddb63caSGarance A Drosehn fhosterr(wantsl, NULL, "connected from invalid port (%s)", 7376ddb63caSGarance A Drosehn serv); 7386ddb63caSGarance A Drosehn } 7396ddb63caSGarance A Drosehn 7406ddb63caSGarance A Drosehn #include <stdarg.h> 7416ddb63caSGarance A Drosehn /* 7426ddb63caSGarance A Drosehn * Handle fatal errors in chkhost. The first message will optionally be sent 7436ddb63caSGarance A Drosehn * to syslog, the second one is sent to the connecting host. If the first 7446ddb63caSGarance A Drosehn * message is NULL, then the same message is used for both. Note that the 7456ddb63caSGarance A Drosehn * argument list for both messages are assumed to be the same (or at least 7466ddb63caSGarance A Drosehn * the initial arguments for one must be EXACTLY the same as the complete 7476ddb63caSGarance A Drosehn * argument list for the other message). 7486ddb63caSGarance A Drosehn * 7496ddb63caSGarance A Drosehn * The idea is that the syslog message is meant for an administrator of a 7506ddb63caSGarance A Drosehn * print server (the host receiving connections), while the usermsg is meant 7516ddb63caSGarance A Drosehn * for a remote user who may or may not be clueful, and may or may not be 7526ddb63caSGarance A Drosehn * doing something nefarious. Some remote users (eg, MS-Windows...) may not 7536ddb63caSGarance A Drosehn * even see whatever message is sent, which is why there's the option to 7546ddb63caSGarance A Drosehn * start 'lpd' with the connection-errors also sent to syslog. 7556ddb63caSGarance A Drosehn * 7566ddb63caSGarance A Drosehn * Given that hostnames can theoretically be fairly long (well, over 250 7576ddb63caSGarance A Drosehn * bytes), it would probably be helpful to have the 'from_host' field at 7586ddb63caSGarance A Drosehn * the end of any error messages which include that info. 7596ddb63caSGarance A Drosehn */ 7606ddb63caSGarance A Drosehn void 7616ddb63caSGarance A Drosehn fhosterr(int dosys, const char *sysmsg, const char *usermsg, ...) 7626ddb63caSGarance A Drosehn { 7636ddb63caSGarance A Drosehn va_list ap; 7646ddb63caSGarance A Drosehn char *sbuf, *ubuf; 7656ddb63caSGarance A Drosehn const char *testone; 7666ddb63caSGarance A Drosehn 7676ddb63caSGarance A Drosehn va_start(ap, usermsg); 7686ddb63caSGarance A Drosehn vasprintf(&ubuf, usermsg, ap); 7696ddb63caSGarance A Drosehn va_end(ap); 7706ddb63caSGarance A Drosehn 7716ddb63caSGarance A Drosehn if (dosys) { 7726ddb63caSGarance A Drosehn sbuf = ubuf; /* assume sysmsg == NULL */ 7736ddb63caSGarance A Drosehn if (sysmsg != NULL) { 7746ddb63caSGarance A Drosehn va_start(ap, usermsg); 7756ddb63caSGarance A Drosehn vasprintf(&sbuf, sysmsg, ap); 7766ddb63caSGarance A Drosehn va_end(ap); 7776ddb63caSGarance A Drosehn } 7786ddb63caSGarance A Drosehn /* 7796ddb63caSGarance A Drosehn * If the first variable-parameter is not the 'from_host', 7806ddb63caSGarance A Drosehn * then first write THAT information as a line to syslog. 7816ddb63caSGarance A Drosehn */ 7826ddb63caSGarance A Drosehn va_start(ap, usermsg); 7836ddb63caSGarance A Drosehn testone = va_arg(ap, const char *); 7846ddb63caSGarance A Drosehn if (testone != from_host) { 7856ddb63caSGarance A Drosehn syslog(LOG_WARNING, "for connection from %s:", from_host); 7866ddb63caSGarance A Drosehn } 7876ddb63caSGarance A Drosehn va_end(ap); 7886ddb63caSGarance A Drosehn 7896ddb63caSGarance A Drosehn /* now write the syslog message */ 7906ddb63caSGarance A Drosehn syslog(LOG_WARNING, "%s", sbuf); 7916ddb63caSGarance A Drosehn } 7926ddb63caSGarance A Drosehn 7936ddb63caSGarance A Drosehn printf("%s [@%s]: %s\n", progname, local_host, ubuf); 7946ddb63caSGarance A Drosehn fflush(stdout); 7956ddb63caSGarance A Drosehn 7966ddb63caSGarance A Drosehn /* 7976ddb63caSGarance A Drosehn * Add a minimal delay before exiting (and disconnecting from the 7986ddb63caSGarance A Drosehn * sending-host). This is just in case that machine responds by 7996ddb63caSGarance A Drosehn * INSTANTLY retrying (and instantly re-failing...). This may also 8006ddb63caSGarance A Drosehn * give the other side more time to read the error message. 8016ddb63caSGarance A Drosehn */ 8026ddb63caSGarance A Drosehn sleep(2); /* a paranoid throttling measure */ 8036ddb63caSGarance A Drosehn exit(1); 8040b561052SJoerg Wunsch } 80536d0e2a3SJoerg Wunsch 80608829865SHajimu UMEMOTO /* setup server socket for specified address family */ 80708829865SHajimu UMEMOTO /* if af is PF_UNSPEC more than one socket may be returned */ 80808829865SHajimu UMEMOTO /* the returned list is dynamically allocated, so caller needs to free it */ 80908829865SHajimu UMEMOTO static int * 810aa4ad562SGarance A Drosehn socksetup(int af, int debuglvl) 81108829865SHajimu UMEMOTO { 81208829865SHajimu UMEMOTO struct addrinfo hints, *res, *r; 81308829865SHajimu UMEMOTO int error, maxs, *s, *socks; 81408829865SHajimu UMEMOTO const int on = 1; 81508829865SHajimu UMEMOTO 81608829865SHajimu UMEMOTO memset(&hints, 0, sizeof(hints)); 81708829865SHajimu UMEMOTO hints.ai_flags = AI_PASSIVE; 81808829865SHajimu UMEMOTO hints.ai_family = af; 81908829865SHajimu UMEMOTO hints.ai_socktype = SOCK_STREAM; 82008829865SHajimu UMEMOTO error = getaddrinfo(NULL, "printer", &hints, &res); 82108829865SHajimu UMEMOTO if (error) { 82208829865SHajimu UMEMOTO syslog(LOG_ERR, "%s", gai_strerror(error)); 82308829865SHajimu UMEMOTO mcleanup(0); 82408829865SHajimu UMEMOTO } 82508829865SHajimu UMEMOTO 82608829865SHajimu UMEMOTO /* Count max number of sockets we may open */ 82708829865SHajimu UMEMOTO for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 82808829865SHajimu UMEMOTO ; 82908829865SHajimu UMEMOTO socks = malloc((maxs + 1) * sizeof(int)); 83008829865SHajimu UMEMOTO if (!socks) { 83108829865SHajimu UMEMOTO syslog(LOG_ERR, "couldn't allocate memory for sockets"); 83208829865SHajimu UMEMOTO mcleanup(0); 83308829865SHajimu UMEMOTO } 83408829865SHajimu UMEMOTO 83508829865SHajimu UMEMOTO *socks = 0; /* num of sockets counter at start of array */ 83608829865SHajimu UMEMOTO s = socks + 1; 83708829865SHajimu UMEMOTO for (r = res; r; r = r->ai_next) { 83808829865SHajimu UMEMOTO *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 83908829865SHajimu UMEMOTO if (*s < 0) { 84008829865SHajimu UMEMOTO syslog(LOG_DEBUG, "socket(): %m"); 84108829865SHajimu UMEMOTO continue; 84208829865SHajimu UMEMOTO } 843aa4ad562SGarance A Drosehn if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) 844aa4ad562SGarance A Drosehn < 0) { 84508829865SHajimu UMEMOTO syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m"); 84608829865SHajimu UMEMOTO close(*s); 84708829865SHajimu UMEMOTO continue; 84808829865SHajimu UMEMOTO } 849aa4ad562SGarance A Drosehn if (debuglvl) 850aa4ad562SGarance A Drosehn if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, &debuglvl, 851aa4ad562SGarance A Drosehn sizeof(debuglvl)) < 0) { 85208829865SHajimu UMEMOTO syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 85308829865SHajimu UMEMOTO close(*s); 85408829865SHajimu UMEMOTO continue; 85508829865SHajimu UMEMOTO } 85608829865SHajimu UMEMOTO #ifdef IPV6_BINDV6ONLY 85708829865SHajimu UMEMOTO if (r->ai_family == AF_INET6) { 85808829865SHajimu UMEMOTO if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY, 85908829865SHajimu UMEMOTO &on, sizeof(on)) < 0) { 86008829865SHajimu UMEMOTO syslog(LOG_ERR, 86108829865SHajimu UMEMOTO "setsockopt (IPV6_BINDV6ONLY): %m"); 86208829865SHajimu UMEMOTO close(*s); 86308829865SHajimu UMEMOTO continue; 86408829865SHajimu UMEMOTO } 86508829865SHajimu UMEMOTO } 86608829865SHajimu UMEMOTO #endif 86708829865SHajimu UMEMOTO if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 86808829865SHajimu UMEMOTO syslog(LOG_DEBUG, "bind(): %m"); 86908829865SHajimu UMEMOTO close(*s); 87008829865SHajimu UMEMOTO continue; 87108829865SHajimu UMEMOTO } 87208829865SHajimu UMEMOTO (*socks)++; 87308829865SHajimu UMEMOTO s++; 87408829865SHajimu UMEMOTO } 87508829865SHajimu UMEMOTO 87608829865SHajimu UMEMOTO if (res) 87708829865SHajimu UMEMOTO freeaddrinfo(res); 87808829865SHajimu UMEMOTO 87908829865SHajimu UMEMOTO if (*socks == 0) { 88008829865SHajimu UMEMOTO syslog(LOG_ERR, "Couldn't bind to any socket"); 88108829865SHajimu UMEMOTO free(socks); 88208829865SHajimu UMEMOTO mcleanup(0); 88308829865SHajimu UMEMOTO } 88408829865SHajimu UMEMOTO return(socks); 88508829865SHajimu UMEMOTO } 886affa0039SGarance A Drosehn 887affa0039SGarance A Drosehn static void 888ba7a1ad7SGarance A Drosehn usage(void) 889affa0039SGarance A Drosehn { 890affa0039SGarance A Drosehn #ifdef INET6 8916ddb63caSGarance A Drosehn fprintf(stderr, "usage: lpd [-cdlpw46] [port#]\n"); 892affa0039SGarance A Drosehn #else 8936ddb63caSGarance A Drosehn fprintf(stderr, "usage: lpd [-cdlpw] [port#]\n"); 894affa0039SGarance A Drosehn #endif 895affa0039SGarance A Drosehn exit(EX_USAGE); 896affa0039SGarance A Drosehn } 897