2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * From: @(#)common.c 8.5 (Berkeley) 4/28/95
43 #include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */
44 __FBSDID("$FreeBSD$");
46 #include <sys/param.h>
47 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
56 #include <dirent.h> /* required for lp.h, not used here */
67 #include "pathnames.h"
70 * 'local_host' is always the hostname of the machine which is running
71 * lpr (lpd, whatever), while 'from_host' either points at 'local_host'
72 * or points at a different buffer when receiving a job from a remote
73 * machine (and that buffer has the hostname of that remote machine).
75 char local_host[MAXHOSTNAMELEN]; /* host running lpd/lpr */
76 const char *from_host = local_host; /* client's machine name */
77 const char *from_ip = ""; /* client machine's IP address */
80 u_char family = PF_UNSPEC;
82 u_char family = PF_INET;
86 * Create a TCP connection to host "rhost" at port "rport".
87 * If rport == 0, then use the printer service port.
88 * Most of this code comes from rcmd.c.
91 getport(const struct printer *pp, const char *rhost, int rport)
93 struct addrinfo hints, *res, *ai;
94 int s, timo = 1, lport = IPPORT_RESERVED - 1;
95 int error, refused = 0;
98 * Get the host address and port number to connect to.
101 fatal(pp, "no remote host to connect to");
102 memset(&hints, 0, sizeof(hints));
103 hints.ai_family = family;
104 hints.ai_socktype = SOCK_STREAM;
105 hints.ai_protocol = 0;
106 error = getaddrinfo(rhost, (rport == 0 ? "printer" : NULL),
109 fatal(pp, "%s\n", gai_strerror(error));
111 ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(rport);
114 * Try connecting to the server.
119 s = rresvport_af(&lport, ai->ai_family);
122 if (errno != EAGAIN) {
127 if (refused && timo <= 16) {
138 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
143 * This used to decrement lport, but the current semantics
144 * of rresvport do not provide such a function (in fact,
145 * rresvport should guarantee that the chosen port will
146 * never result in an EADDRINUSE).
148 if (errno == EADDRINUSE) {
152 if (errno == ECONNREFUSED)
155 if (ai->ai_next != NULL) {
159 if (refused && timo <= 16) {
174 * Figure out whether the local machine is the same
175 * as the remote machine (RM) entry (if it exists).
176 * We do this by counting the intersection of our
177 * address list and theirs. This is better than the
178 * old method (comparing the canonical names), as it
179 * allows load-sharing between multiple print servers.
180 * The return value is an error message which must be
184 checkremote(struct printer *pp)
186 char lclhost[MAXHOSTNAMELEN];
187 struct addrinfo hints, *local_res, *remote_res, *lr, *rr;
189 int ncommonaddrs, errno;
190 char h1[NI_MAXHOST], h2[NI_MAXHOST];
192 if (!pp->rp_matches_local) { /* Remote printer doesn't match local */
197 pp->remote = 0; /* assume printer is local */
198 if (pp->remote_host == NULL)
201 /* get the addresses of the local host */
202 gethostname(lclhost, sizeof(lclhost));
203 lclhost[sizeof(lclhost) - 1] = '\0';
205 memset(&hints, 0, sizeof(hints));
206 hints.ai_family = family;
207 hints.ai_socktype = SOCK_STREAM;
208 hints.ai_flags = AI_PASSIVE;
209 if ((errno = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) {
210 asprintf(&error, "unable to get official name "
211 "for local machine %s: %s",
212 lclhost, gai_strerror(errno));
216 /* get the official name of RM */
217 memset(&hints, 0, sizeof(hints));
218 hints.ai_family = family;
219 hints.ai_socktype = SOCK_STREAM;
220 hints.ai_flags = AI_PASSIVE;
221 if ((errno = getaddrinfo(pp->remote_host, NULL,
222 &hints, &remote_res)) != 0) {
223 asprintf(&error, "unable to get address list for "
224 "remote machine %s: %s",
225 pp->remote_host, gai_strerror(errno));
226 freeaddrinfo(local_res);
231 for (lr = local_res; lr; lr = lr->ai_next) {
233 if (getnameinfo(lr->ai_addr, lr->ai_addrlen, h1, sizeof(h1),
234 NULL, 0, NI_NUMERICHOST) != 0)
236 for (rr = remote_res; rr; rr = rr->ai_next) {
238 if (getnameinfo(rr->ai_addr, rr->ai_addrlen,
239 h2, sizeof(h2), NULL, 0,
240 NI_NUMERICHOST) != 0)
242 if (strcmp(h1, h2) == 0)
248 * if the two hosts do not share at least one IP address
249 * then the printer must be remote.
251 if (ncommonaddrs == 0)
253 freeaddrinfo(local_res);
254 freeaddrinfo(remote_res);
259 * This isn't really network-related, but it's used here to write
260 * multi-part strings onto sockets without using stdio. Return
261 * values are as for writev(2).
264 writel(int strm, ...)
270 struct iovec iov[NIOV], *iovp = iov;
273 /* first count them */
277 cp = va_arg(ap, char *);
281 n--; /* correct for count of trailing null */
284 iovp = malloc(n * sizeof *iovp);
289 /* now make up iovec and send */
291 for (i = 0; i < n; i++) {
292 iovp[i].iov_base = va_arg(ap, char *);
293 iovp[i].iov_len = strlen(iovp[i].iov_base);
296 retval = writev(strm, iovp, n);