xref: /freebsd/usr.sbin/lpr/common_source/net.c (revision 1d1d4a47)
14a1a0dbeSGarrett Wollman /*
24a1a0dbeSGarrett Wollman  * Copyright (c) 1983, 1993
34a1a0dbeSGarrett Wollman  *	The Regents of the University of California.  All rights reserved.
44a1a0dbeSGarrett Wollman  * (c) UNIX System Laboratories, Inc.
54a1a0dbeSGarrett Wollman  * All or some portions of this file are derived from material licensed
64a1a0dbeSGarrett Wollman  * to the University of California by American Telephone and Telegraph
74a1a0dbeSGarrett Wollman  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
84a1a0dbeSGarrett Wollman  * the permission of UNIX System Laboratories, Inc.
94a1a0dbeSGarrett Wollman  *
104a1a0dbeSGarrett Wollman  * Redistribution and use in source and binary forms, with or without
114a1a0dbeSGarrett Wollman  * modification, are permitted provided that the following conditions
124a1a0dbeSGarrett Wollman  * are met:
134a1a0dbeSGarrett Wollman  * 1. Redistributions of source code must retain the above copyright
144a1a0dbeSGarrett Wollman  *    notice, this list of conditions and the following disclaimer.
154a1a0dbeSGarrett Wollman  * 2. Redistributions in binary form must reproduce the above copyright
164a1a0dbeSGarrett Wollman  *    notice, this list of conditions and the following disclaimer in the
174a1a0dbeSGarrett Wollman  *    documentation and/or other materials provided with the distribution.
184a1a0dbeSGarrett Wollman  * 3. All advertising materials mentioning features or use of this software
194a1a0dbeSGarrett Wollman  *    must display the following acknowledgement:
204a1a0dbeSGarrett Wollman  *	This product includes software developed by the University of
214a1a0dbeSGarrett Wollman  *	California, Berkeley and its contributors.
224a1a0dbeSGarrett Wollman  * 4. Neither the name of the University nor the names of its contributors
234a1a0dbeSGarrett Wollman  *    may be used to endorse or promote products derived from this software
244a1a0dbeSGarrett Wollman  *    without specific prior written permission.
254a1a0dbeSGarrett Wollman  *
264a1a0dbeSGarrett Wollman  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
274a1a0dbeSGarrett Wollman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
284a1a0dbeSGarrett Wollman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
294a1a0dbeSGarrett Wollman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
304a1a0dbeSGarrett Wollman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
314a1a0dbeSGarrett Wollman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
324a1a0dbeSGarrett Wollman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
334a1a0dbeSGarrett Wollman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
344a1a0dbeSGarrett Wollman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
354a1a0dbeSGarrett Wollman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
364a1a0dbeSGarrett Wollman  * SUCH DAMAGE.
374a1a0dbeSGarrett Wollman  *
384a1a0dbeSGarrett Wollman  *	From: @(#)common.c	8.5 (Berkeley) 4/28/95
394a1a0dbeSGarrett Wollman  */
404a1a0dbeSGarrett Wollman 
411f589b47SGarance A Drosehn #include "lp.cdefs.h"		/* A cross-platform version of <sys/cdefs.h> */
421f589b47SGarance A Drosehn __FBSDID("$FreeBSD$");
434a1a0dbeSGarrett Wollman 
444a1a0dbeSGarrett Wollman #include <sys/param.h>
454a1a0dbeSGarrett Wollman #include <sys/socket.h>
464a1a0dbeSGarrett Wollman #include <sys/stat.h>
474a1a0dbeSGarrett Wollman #include <sys/time.h>
484a1a0dbeSGarrett Wollman #include <sys/uio.h>
494a1a0dbeSGarrett Wollman 
504a1a0dbeSGarrett Wollman #include <netinet/in.h>
514a1a0dbeSGarrett Wollman #include <arpa/inet.h>
524a1a0dbeSGarrett Wollman #include <netdb.h>
534a1a0dbeSGarrett Wollman 
544a1a0dbeSGarrett Wollman #include <dirent.h>		/* required for lp.h, not used here */
551d1d4a47SEitan Adler #include <err.h>
564a1a0dbeSGarrett Wollman #include <errno.h>
574a1a0dbeSGarrett Wollman #include <stdarg.h>
584a1a0dbeSGarrett Wollman #include <stdio.h>
594a1a0dbeSGarrett Wollman #include <stdlib.h>
604a1a0dbeSGarrett Wollman #include <string.h>
614a1a0dbeSGarrett Wollman #include <unistd.h>
624a1a0dbeSGarrett Wollman 
634a1a0dbeSGarrett Wollman #include "lp.h"
644a1a0dbeSGarrett Wollman #include "lp.local.h"
654a1a0dbeSGarrett Wollman #include "pathnames.h"
664a1a0dbeSGarrett Wollman 
67cc3fd56fSGarance A Drosehn /*
68cc3fd56fSGarance A Drosehn  * 'local_host' is always the hostname of the machine which is running
69cc3fd56fSGarance A Drosehn  * lpr (lpd, whatever), while 'from_host' either points at 'local_host'
70cc3fd56fSGarance A Drosehn  * or points at a different buffer when receiving a job from a remote
71cc3fd56fSGarance A Drosehn  * machine (and that buffer has the hostname of that remote machine).
72cc3fd56fSGarance A Drosehn  */
73cc3fd56fSGarance A Drosehn char		 local_host[MAXHOSTNAMELEN];	/* host running lpd/lpr */
74cc3fd56fSGarance A Drosehn const char	*from_host = local_host;	/* client's machine name */
75cc3fd56fSGarance A Drosehn const char	*from_ip = "";		/* client machine's IP address */
7608829865SHajimu UMEMOTO 
7708829865SHajimu UMEMOTO #ifdef INET6
7808829865SHajimu UMEMOTO u_char	family = PF_UNSPEC;
7908829865SHajimu UMEMOTO #else
8008829865SHajimu UMEMOTO u_char	family = PF_INET;
8108829865SHajimu UMEMOTO #endif
824a1a0dbeSGarrett Wollman 
834a1a0dbeSGarrett Wollman extern uid_t	uid, euid;
844a1a0dbeSGarrett Wollman 
854a1a0dbeSGarrett Wollman /*
864a1a0dbeSGarrett Wollman  * Create a TCP connection to host "rhost" at port "rport".
874a1a0dbeSGarrett Wollman  * If rport == 0, then use the printer service port.
884a1a0dbeSGarrett Wollman  * Most of this code comes from rcmd.c.
894a1a0dbeSGarrett Wollman  */
904a1a0dbeSGarrett Wollman int
914a1a0dbeSGarrett Wollman getport(const struct printer *pp, const char *rhost, int rport)
924a1a0dbeSGarrett Wollman {
9308829865SHajimu UMEMOTO 	struct addrinfo hints, *res, *ai;
944a1a0dbeSGarrett Wollman 	int s, timo = 1, lport = IPPORT_RESERVED - 1;
951d1d4a47SEitan Adler 	int error, refused = 0;
964a1a0dbeSGarrett Wollman 
974a1a0dbeSGarrett Wollman 	/*
984a1a0dbeSGarrett Wollman 	 * Get the host address and port number to connect to.
994a1a0dbeSGarrett Wollman 	 */
1004a1a0dbeSGarrett Wollman 	if (rhost == NULL)
1014a1a0dbeSGarrett Wollman 		fatal(pp, "no remote host to connect to");
10208829865SHajimu UMEMOTO 	memset(&hints, 0, sizeof(hints));
10308829865SHajimu UMEMOTO 	hints.ai_family = family;
10408829865SHajimu UMEMOTO 	hints.ai_socktype = SOCK_STREAM;
10508829865SHajimu UMEMOTO 	hints.ai_protocol = 0;
1061d1d4a47SEitan Adler 	error = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL),
10708829865SHajimu UMEMOTO 			  &hints, &res);
1081d1d4a47SEitan Adler 	if (error)
1091d1d4a47SEitan Adler 		fatal(pp, "%s\n", gai_strerror(error));
11008829865SHajimu UMEMOTO 	if (rport != 0)
11108829865SHajimu UMEMOTO 		((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport);
1124a1a0dbeSGarrett Wollman 
1134a1a0dbeSGarrett Wollman 	/*
1144a1a0dbeSGarrett Wollman 	 * Try connecting to the server.
1154a1a0dbeSGarrett Wollman 	 */
11608829865SHajimu UMEMOTO 	ai = res;
1174a1a0dbeSGarrett Wollman retry:
1181d1d4a47SEitan Adler 	PRIV_START
11908829865SHajimu UMEMOTO 	s = rresvport_af(&lport, ai->ai_family);
1201d1d4a47SEitan Adler 	PRIV_END
12108829865SHajimu UMEMOTO 	if (s < 0) {
12208829865SHajimu UMEMOTO 		if (errno != EAGAIN) {
12308829865SHajimu UMEMOTO 			if (ai->ai_next) {
12408829865SHajimu UMEMOTO 				ai = ai->ai_next;
12508829865SHajimu UMEMOTO 				goto retry;
12608829865SHajimu UMEMOTO 			}
12708829865SHajimu UMEMOTO 			if (refused && timo <= 16) {
12808829865SHajimu UMEMOTO 				sleep(timo);
12908829865SHajimu UMEMOTO 				timo *= 2;
13008829865SHajimu UMEMOTO 				refused = 0;
13108829865SHajimu UMEMOTO 				ai = res;
13208829865SHajimu UMEMOTO 				goto retry;
13308829865SHajimu UMEMOTO 			}
13408829865SHajimu UMEMOTO 		}
13508829865SHajimu UMEMOTO 		freeaddrinfo(res);
1364a1a0dbeSGarrett Wollman 		return(-1);
13708829865SHajimu UMEMOTO 	}
13808829865SHajimu UMEMOTO 	if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
1391d1d4a47SEitan Adler 		error = errno;
1404a1a0dbeSGarrett Wollman 		(void) close(s);
1411d1d4a47SEitan Adler 		errno = error;
1424a1a0dbeSGarrett Wollman 		/*
1434a1a0dbeSGarrett Wollman 		 * This used to decrement lport, but the current semantics
1444a1a0dbeSGarrett Wollman 		 * of rresvport do not provide such a function (in fact,
1454a1a0dbeSGarrett Wollman 		 * rresvport should guarantee that the chosen port will
1464a1a0dbeSGarrett Wollman 		 * never result in an EADDRINUSE).
1474a1a0dbeSGarrett Wollman 		 */
14808829865SHajimu UMEMOTO 		if (errno == EADDRINUSE) {
1494a1a0dbeSGarrett Wollman 			goto retry;
15008829865SHajimu UMEMOTO 		}
1514a1a0dbeSGarrett Wollman 
15208829865SHajimu UMEMOTO 		if (errno == ECONNREFUSED)
15308829865SHajimu UMEMOTO 			refused++;
15408829865SHajimu UMEMOTO 
15508829865SHajimu UMEMOTO 		if (ai->ai_next != NULL) {
15608829865SHajimu UMEMOTO 			ai = ai->ai_next;
15708829865SHajimu UMEMOTO 			goto retry;
15808829865SHajimu UMEMOTO 		}
15908829865SHajimu UMEMOTO 		if (refused && timo <= 16) {
1604a1a0dbeSGarrett Wollman 			sleep(timo);
1614a1a0dbeSGarrett Wollman 			timo *= 2;
16208829865SHajimu UMEMOTO 			refused = 0;
16308829865SHajimu UMEMOTO 			ai = res;
1644a1a0dbeSGarrett Wollman 			goto retry;
1654a1a0dbeSGarrett Wollman 		}
16608829865SHajimu UMEMOTO 		freeaddrinfo(res);
1674a1a0dbeSGarrett Wollman 		return(-1);
1684a1a0dbeSGarrett Wollman 	}
16908829865SHajimu UMEMOTO 	freeaddrinfo(res);
1704a1a0dbeSGarrett Wollman 	return(s);
1714a1a0dbeSGarrett Wollman }
1724a1a0dbeSGarrett Wollman 
1734a1a0dbeSGarrett Wollman /*
1744a1a0dbeSGarrett Wollman  * Figure out whether the local machine is the same
1754a1a0dbeSGarrett Wollman  * as the remote machine (RM) entry (if it exists).
1764a1a0dbeSGarrett Wollman  * We do this by counting the intersection of our
1774a1a0dbeSGarrett Wollman  * address list and theirs.  This is better than the
1784a1a0dbeSGarrett Wollman  * old method (comparing the canonical names), as it
1794a1a0dbeSGarrett Wollman  * allows load-sharing between multiple print servers.
1804a1a0dbeSGarrett Wollman  * The return value is an error message which must be
1814a1a0dbeSGarrett Wollman  * free()d.
1824a1a0dbeSGarrett Wollman  */
1834a1a0dbeSGarrett Wollman char *
1844a1a0dbeSGarrett Wollman checkremote(struct printer *pp)
1854a1a0dbeSGarrett Wollman {
186ba7a1ad7SGarance A Drosehn 	char lclhost[MAXHOSTNAMELEN];
18708829865SHajimu UMEMOTO 	struct addrinfo hints, *local_res, *remote_res, *lr, *rr;
1881d1d4a47SEitan Adler 	char *error;
1891d1d4a47SEitan Adler 	int ncommonaddrs, errno;
19008829865SHajimu UMEMOTO 	char h1[NI_MAXHOST], h2[NI_MAXHOST];
1914a1a0dbeSGarrett Wollman 
192d5483ddfSJordan K. Hubbard 	if (!pp->rp_matches_local) { /* Remote printer doesn't match local */
193d5483ddfSJordan K. Hubbard 		pp->remote = 1;
194d5483ddfSJordan K. Hubbard 		return NULL;
195d5483ddfSJordan K. Hubbard 	}
196d5483ddfSJordan K. Hubbard 
1974a1a0dbeSGarrett Wollman 	pp->remote = 0;	/* assume printer is local */
19808829865SHajimu UMEMOTO 	if (pp->remote_host == NULL)
19908829865SHajimu UMEMOTO 		return NULL;
20008829865SHajimu UMEMOTO 
2014a1a0dbeSGarrett Wollman 	/* get the addresses of the local host */
202ba7a1ad7SGarance A Drosehn 	gethostname(lclhost, sizeof(lclhost));
203ba7a1ad7SGarance A Drosehn 	lclhost[sizeof(lclhost) - 1] = '\0';
20408829865SHajimu UMEMOTO 
20508829865SHajimu UMEMOTO 	memset(&hints, 0, sizeof(hints));
20608829865SHajimu UMEMOTO 	hints.ai_family = family;
20708829865SHajimu UMEMOTO 	hints.ai_socktype = SOCK_STREAM;
20808829865SHajimu UMEMOTO 	hints.ai_flags = AI_PASSIVE;
2091d1d4a47SEitan Adler 	if ((errno = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) {
2101d1d4a47SEitan Adler 		asprintf(&error, "unable to get official name "
2114a1a0dbeSGarrett Wollman 			 "for local machine %s: %s",
2121d1d4a47SEitan Adler 			 lclhost, gai_strerror(errno));
2131d1d4a47SEitan Adler 		return error;
2144a1a0dbeSGarrett Wollman 	}
2154a1a0dbeSGarrett Wollman 
2164a1a0dbeSGarrett Wollman 	/* get the official name of RM */
21708829865SHajimu UMEMOTO 	memset(&hints, 0, sizeof(hints));
21808829865SHajimu UMEMOTO 	hints.ai_family = family;
21908829865SHajimu UMEMOTO 	hints.ai_socktype = SOCK_STREAM;
22008829865SHajimu UMEMOTO 	hints.ai_flags = AI_PASSIVE;
2211d1d4a47SEitan Adler 	if ((errno = getaddrinfo(pp->remote_host, NULL,
22208829865SHajimu UMEMOTO 				 &hints, &remote_res)) != 0) {
2231d1d4a47SEitan Adler 		asprintf(&error, "unable to get address list for "
2244a1a0dbeSGarrett Wollman 			 "remote machine %s: %s",
2251d1d4a47SEitan Adler 			 pp->remote_host, gai_strerror(errno));
22608829865SHajimu UMEMOTO 		freeaddrinfo(local_res);
2271d1d4a47SEitan Adler 		return error;
2284a1a0dbeSGarrett Wollman 	}
2294a1a0dbeSGarrett Wollman 
2304a1a0dbeSGarrett Wollman 	ncommonaddrs = 0;
23108829865SHajimu UMEMOTO 	for (lr = local_res; lr; lr = lr->ai_next) {
23208829865SHajimu UMEMOTO 		h1[0] = '\0';
23308829865SHajimu UMEMOTO 		if (getnameinfo(lr->ai_addr, lr->ai_addrlen, h1, sizeof(h1),
2349ccf2f38SHajimu UMEMOTO 				NULL, 0, NI_NUMERICHOST) != 0)
23508829865SHajimu UMEMOTO 			continue;
23608829865SHajimu UMEMOTO 		for (rr = remote_res; rr; rr = rr->ai_next) {
23708829865SHajimu UMEMOTO 			h2[0] = '\0';
23808829865SHajimu UMEMOTO 			if (getnameinfo(rr->ai_addr, rr->ai_addrlen,
23908829865SHajimu UMEMOTO 					h2, sizeof(h2), NULL, 0,
2409ccf2f38SHajimu UMEMOTO 					NI_NUMERICHOST) != 0)
24108829865SHajimu UMEMOTO 				continue;
24208829865SHajimu UMEMOTO 			if (strcmp(h1, h2) == 0)
2434a1a0dbeSGarrett Wollman 				ncommonaddrs++;
2444a1a0dbeSGarrett Wollman 		}
2454a1a0dbeSGarrett Wollman 	}
2464a1a0dbeSGarrett Wollman 
2474a1a0dbeSGarrett Wollman 	/*
2484a1a0dbeSGarrett Wollman 	 * if the two hosts do not share at least one IP address
2494a1a0dbeSGarrett Wollman 	 * then the printer must be remote.
2504a1a0dbeSGarrett Wollman 	 */
2514a1a0dbeSGarrett Wollman 	if (ncommonaddrs == 0)
2524a1a0dbeSGarrett Wollman 		pp->remote = 1;
25308829865SHajimu UMEMOTO 	freeaddrinfo(local_res);
25408829865SHajimu UMEMOTO 	freeaddrinfo(remote_res);
2554a1a0dbeSGarrett Wollman 	return NULL;
2564a1a0dbeSGarrett Wollman }
2574a1a0dbeSGarrett Wollman 
2584a1a0dbeSGarrett Wollman /*
2594a1a0dbeSGarrett Wollman  * This isn't really network-related, but it's used here to write
2604a1a0dbeSGarrett Wollman  * multi-part strings onto sockets without using stdio.  Return
2614a1a0dbeSGarrett Wollman  * values are as for writev(2).
2624a1a0dbeSGarrett Wollman  */
2634a1a0dbeSGarrett Wollman ssize_t
264ba7a1ad7SGarance A Drosehn writel(int strm, ...)
2654a1a0dbeSGarrett Wollman {
2664a1a0dbeSGarrett Wollman 	va_list ap;
2674a1a0dbeSGarrett Wollman 	int i, n;
2684a1a0dbeSGarrett Wollman 	const char *cp;
2694a1a0dbeSGarrett Wollman #define NIOV 12
2704a1a0dbeSGarrett Wollman 	struct iovec iov[NIOV], *iovp = iov;
2714a1a0dbeSGarrett Wollman 	ssize_t retval;
2724a1a0dbeSGarrett Wollman 
2734a1a0dbeSGarrett Wollman 	/* first count them */
274ba7a1ad7SGarance A Drosehn 	va_start(ap, strm);
2754a1a0dbeSGarrett Wollman 	n = 0;
2764a1a0dbeSGarrett Wollman 	do {
2774a1a0dbeSGarrett Wollman 		cp = va_arg(ap, char *);
2784a1a0dbeSGarrett Wollman 		n++;
2794a1a0dbeSGarrett Wollman 	} while (cp);
2804a1a0dbeSGarrett Wollman 	va_end(ap);
2814a1a0dbeSGarrett Wollman 	n--;			/* correct for count of trailing null */
2824a1a0dbeSGarrett Wollman 
2834a1a0dbeSGarrett Wollman 	if (n > NIOV) {
2844a1a0dbeSGarrett Wollman 		iovp = malloc(n * sizeof *iovp);
2854a1a0dbeSGarrett Wollman 		if (iovp == 0)
2864a1a0dbeSGarrett Wollman 			return -1;
2874a1a0dbeSGarrett Wollman 	}
2884a1a0dbeSGarrett Wollman 
2894a1a0dbeSGarrett Wollman 	/* now make up iovec and send */
290ba7a1ad7SGarance A Drosehn 	va_start(ap, strm);
2914a1a0dbeSGarrett Wollman 	for (i = 0; i < n; i++) {
2924a1a0dbeSGarrett Wollman 		iovp[i].iov_base = va_arg(ap, char *);
2934a1a0dbeSGarrett Wollman 		iovp[i].iov_len = strlen(iovp[i].iov_base);
2944a1a0dbeSGarrett Wollman 	}
2954a1a0dbeSGarrett Wollman 	va_end(ap);
296ba7a1ad7SGarance A Drosehn 	retval = writev(strm, iovp, n);
2974a1a0dbeSGarrett Wollman 	if (iovp != iov)
2984a1a0dbeSGarrett Wollman 		free(iovp);
2994a1a0dbeSGarrett Wollman 	return retval;
3004a1a0dbeSGarrett Wollman }
301