2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * From: @(#)common.c 8.5 (Berkeley) 4/28/95
40 * $FreeBSD: src/usr.sbin/lpr/common_source/net.c,v 1.3.2.4 2001/06/25 01:00:56 gad Exp $
41 * $DragonFly: src/usr.sbin/lpr/common_source/net.c,v 1.3 2004/12/18 22:48:03 swildner Exp $
44 #include <sys/param.h>
45 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
54 #include <dirent.h> /* required for lp.h, not used here */
64 #include "pathnames.h"
67 * 'local_host' is always the hostname of the machine which is running
68 * lpr (lpd, whatever), while 'from_host' either points at 'local_host'
69 * or points at a different buffer when receiving a job from a remote
70 * machine (and that buffer has the hostname of that remote machine).
72 char local_host
[MAXHOSTNAMELEN
]; /* host running lpd/lpr */
73 const char *from_host
= local_host
; /* client's machine name */
74 const char *from_ip
= ""; /* client machine's IP address */
77 u_char family
= PF_UNSPEC
;
79 u_char family
= PF_INET
;
82 extern uid_t uid
, euid
;
85 * Create a TCP connection to host "rhost" at port "rport".
86 * If rport == 0, then use the printer service port.
87 * Most of this code comes from rcmd.c.
90 getport(const struct printer
*pp
, const char *rhost
, int rport
)
92 struct addrinfo hints
, *res
, *ai
;
93 int s
, timo
= 1, lport
= IPPORT_RESERVED
- 1;
97 * Get the host address and port number to connect to.
100 fatal(pp
, "no remote host to connect to");
101 memset(&hints
, 0, sizeof(hints
));
102 hints
.ai_family
= family
;
103 hints
.ai_socktype
= SOCK_STREAM
;
104 hints
.ai_protocol
= 0;
105 err
= getaddrinfo(rhost
, (rport
== 0 ? "printer" : NULL
),
108 fatal(pp
, "%s\n", gai_strerror(err
));
110 ((struct sockaddr_in
*) res
->ai_addr
)->sin_port
= htons(rport
);
113 * Try connecting to the server.
118 s
= rresvport_af(&lport
, ai
->ai_family
);
121 if (errno
!= EAGAIN
) {
126 if (refused
&& timo
<= 16) {
137 if (connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) < 0) {
142 * This used to decrement lport, but the current semantics
143 * of rresvport do not provide such a function (in fact,
144 * rresvport should guarantee that the chosen port will
145 * never result in an EADDRINUSE).
147 if (errno
== EADDRINUSE
) {
151 if (errno
== ECONNREFUSED
)
154 if (ai
->ai_next
!= NULL
) {
158 if (refused
&& timo
<= 16) {
173 * Figure out whether the local machine is the same
174 * as the remote machine (RM) entry (if it exists).
175 * We do this by counting the intersection of our
176 * address list and theirs. This is better than the
177 * old method (comparing the canonical names), as it
178 * allows load-sharing between multiple print servers.
179 * The return value is an error message which must be
183 checkremote(struct printer
*pp
)
185 char lclhost
[MAXHOSTNAMELEN
];
186 struct addrinfo hints
, *local_res
, *remote_res
, *lr
, *rr
;
188 int ncommonaddrs
, error
;
189 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
191 if (!pp
->rp_matches_local
) { /* Remote printer doesn't match local */
196 pp
->remote
= 0; /* assume printer is local */
197 if (pp
->remote_host
== NULL
)
200 /* get the addresses of the local host */
201 gethostname(lclhost
, sizeof(lclhost
));
202 lclhost
[sizeof(lclhost
) - 1] = '\0';
204 memset(&hints
, 0, sizeof(hints
));
205 hints
.ai_family
= family
;
206 hints
.ai_socktype
= SOCK_STREAM
;
207 hints
.ai_flags
= AI_PASSIVE
;
208 if ((error
= getaddrinfo(lclhost
, NULL
, &hints
, &local_res
)) != 0) {
209 asprintf(&err
, "unable to get official name "
210 "for local machine %s: %s",
211 lclhost
, gai_strerror(error
));
215 /* get the official name of RM */
216 memset(&hints
, 0, sizeof(hints
));
217 hints
.ai_family
= family
;
218 hints
.ai_socktype
= SOCK_STREAM
;
219 hints
.ai_flags
= AI_PASSIVE
;
220 if ((error
= getaddrinfo(pp
->remote_host
, NULL
,
221 &hints
, &remote_res
)) != 0) {
222 asprintf(&err
, "unable to get address list for "
223 "remote machine %s: %s",
224 pp
->remote_host
, gai_strerror(error
));
225 freeaddrinfo(local_res
);
230 for (lr
= local_res
; lr
; lr
= lr
->ai_next
) {
232 if (getnameinfo(lr
->ai_addr
, lr
->ai_addrlen
, h1
, sizeof(h1
),
233 NULL
, 0, NI_NUMERICHOST
| NI_WITHSCOPEID
) != 0)
235 for (rr
= remote_res
; rr
; rr
= rr
->ai_next
) {
237 if (getnameinfo(rr
->ai_addr
, rr
->ai_addrlen
,
238 h2
, sizeof(h2
), NULL
, 0,
239 NI_NUMERICHOST
| NI_WITHSCOPEID
) != 0)
241 if (strcmp(h1
, h2
) == 0)
247 * if the two hosts do not share at least one IP address
248 * then the printer must be remote.
250 if (ncommonaddrs
== 0)
252 freeaddrinfo(local_res
);
253 freeaddrinfo(remote_res
);
258 * This isn't really network-related, but it's used here to write
259 * multi-part strings onto sockets without using stdio. Return
260 * values are as for writev(2).
263 writel(int strm
, ...)
269 struct iovec iov
[NIOV
], *iovp
= iov
;
272 /* first count them */
276 cp
= va_arg(ap
, char *);
280 n
--; /* correct for count of trailing null */
283 iovp
= malloc(n
* sizeof *iovp
);
288 /* now make up iovec and send */
290 for (i
= 0; i
< n
; i
++) {
291 iovp
[i
].iov_base
= va_arg(ap
, char *);
292 iovp
[i
].iov_len
= strlen(iovp
[i
].iov_base
);
295 retval
= writev(strm
, iovp
, n
);